mirror of
https://github.com/hmalik144/days_left_flutter.git
synced 2025-12-10 03:05:21 +00:00
- Introduction on base view model and stateless widget classes
- Implementation of firebase - Implementation of dependency injection Took 11 hours 26 minutes
This commit is contained in:
13
lib/Utils/ViewUtils.dart
Normal file
13
lib/Utils/ViewUtils.dart
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:toast/toast.dart';
|
||||||
|
|
||||||
|
class ViewUtils{
|
||||||
|
|
||||||
|
static displayToast(BuildContext context, String message){
|
||||||
|
Toast.show(
|
||||||
|
message, context,
|
||||||
|
duration: Toast.LENGTH_SHORT,
|
||||||
|
gravity: Toast.BOTTOM
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
41
lib/base/BaseModel.dart
Normal file
41
lib/base/BaseModel.dart
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:days_left/data/ViewState.dart';
|
||||||
|
import 'package:stacked/stacked.dart';
|
||||||
|
|
||||||
|
class BaseModel extends BaseViewModel {
|
||||||
|
ViewState _viewState = Idle();
|
||||||
|
|
||||||
|
ViewState get viewState => _viewState;
|
||||||
|
|
||||||
|
void onStart() {
|
||||||
|
_viewState = HasStarted();
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onSuccess(dynamic data) {
|
||||||
|
_viewState = HasData(data);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onError(String error) {
|
||||||
|
_viewState = HasError(error);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleFuture(Future<dynamic> func) {
|
||||||
|
onStart();
|
||||||
|
func.then((value) => onSuccess(value)).catchError((error) {
|
||||||
|
print(error);
|
||||||
|
onError(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleStream(Stream<dynamic> stream) {
|
||||||
|
stream.listen((event) {
|
||||||
|
onSuccess(event);
|
||||||
|
}).onError((handleError) {
|
||||||
|
onError(handleError);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
32
lib/base/BaseStatelessWidget.dart
Normal file
32
lib/base/BaseStatelessWidget.dart
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import 'package:days_left/Utils/ViewUtils.dart';
|
||||||
|
import 'package:days_left/data/ViewState.dart';
|
||||||
|
import 'BaseModel.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:stacked/stacked.dart';
|
||||||
|
|
||||||
|
abstract class BaseStatelessWidget extends StatelessWidget {
|
||||||
|
BaseModel getBaseModel();
|
||||||
|
Widget displayWidget(context, model, child);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext parent) {
|
||||||
|
return ViewModelBuilder<BaseModel>.reactive(
|
||||||
|
builder: (context, model, child) {
|
||||||
|
var state = model.viewState;
|
||||||
|
|
||||||
|
if (state is HasStarted)
|
||||||
|
return Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
);
|
||||||
|
else if (state is HasError)
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback(
|
||||||
|
(_) => ViewUtils.displayToast(parent, state.error));
|
||||||
|
|
||||||
|
return Center(
|
||||||
|
child: displayWidget(context, model, child),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
viewModelBuilder: () => getBaseModel());
|
||||||
|
}
|
||||||
|
}
|
||||||
12
lib/constants/constants.dart
Normal file
12
lib/constants/constants.dart
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
const String PhoneNoViewRoute = "PhoneNo";
|
||||||
|
const String CodeViewRoute = "Code";
|
||||||
|
const String HomeViewRoute = "Home";
|
||||||
|
const String UpdateDetailsViewRoute = "UpdateDetails";
|
||||||
|
const String AddTestsViewRoute = "AddTests";
|
||||||
|
const String TestListViewRoute = "TestList";
|
||||||
|
const String TestOverviewViewRoute = "TestOverview";
|
||||||
|
const String LoginViewRoute = "Login";
|
||||||
|
|
||||||
|
const String HasStarted = "hasStarted";
|
||||||
|
const String HasData = "hasData";
|
||||||
|
const String HasError = "hasError";
|
||||||
49
lib/data/FirebaseAuthData.dart
Normal file
49
lib/data/FirebaseAuthData.dart
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
// import 'package:firebase_auth/firebase_auth.dart';
|
||||||
|
|
||||||
|
import 'package:firebase_auth/firebase_auth.dart';
|
||||||
|
|
||||||
|
class FirebaseAuthData {
|
||||||
|
final FirebaseAuth firebaseAuth = FirebaseAuth.instance;
|
||||||
|
|
||||||
|
User getUser() {
|
||||||
|
return firebaseAuth.currentUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getUid() {
|
||||||
|
return getUser()?.uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<UserCredential> signUpWithEmailAndPassword(
|
||||||
|
String email, String password) {
|
||||||
|
return firebaseAuth.createUserWithEmailAndPassword(
|
||||||
|
email: email, password: password);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<UserCredential> signIn(String email, String password) {
|
||||||
|
return firebaseAuth.signInWithEmailAndPassword(
|
||||||
|
email: email, password: password);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> resetPassword(String email) {
|
||||||
|
return firebaseAuth.sendPasswordResetEmail(email: email);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> signOut() {
|
||||||
|
return firebaseAuth.signOut();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> updateUsername(String newEmail) {
|
||||||
|
return getUser().updateEmail(newEmail);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> updatePassword(
|
||||||
|
String email, String password, String newPassword) async {
|
||||||
|
UserCredential credentials = await signIn(email, password);
|
||||||
|
return credentials.user.updatePassword(newPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> updateProfile({String displayName, String photoURL}) {
|
||||||
|
return getUser()
|
||||||
|
.updateProfile(displayName: displayName, photoURL: photoURL);
|
||||||
|
}
|
||||||
|
}
|
||||||
20
lib/data/ViewState.dart
Normal file
20
lib/data/ViewState.dart
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import 'package:sealed_class/sealed_class.dart';
|
||||||
|
|
||||||
|
@Sealed([Idle, HasStarted, HasData, HasError])
|
||||||
|
abstract class ViewState {}
|
||||||
|
|
||||||
|
class Idle implements ViewState {}
|
||||||
|
|
||||||
|
class HasStarted implements ViewState {}
|
||||||
|
|
||||||
|
class HasData implements ViewState {
|
||||||
|
final dynamic data;
|
||||||
|
|
||||||
|
HasData(this.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
class HasError implements ViewState {
|
||||||
|
final String error;
|
||||||
|
|
||||||
|
HasError(this.error);
|
||||||
|
}
|
||||||
17
lib/locator.dart
Normal file
17
lib/locator.dart
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import 'package:days_left/viewmodels/LoginViewModel.dart';
|
||||||
|
import 'package:days_left/viewmodels/UserAuthViewModel.dart';
|
||||||
|
import 'package:get_it/get_it.dart';
|
||||||
|
import 'data/FirebaseAuthData.dart';
|
||||||
|
import 'services/DialogService.dart';
|
||||||
|
import 'services/NavigationService.dart';
|
||||||
|
|
||||||
|
GetIt locator = GetIt.instance;
|
||||||
|
|
||||||
|
void setupLocator() {
|
||||||
|
final FirebaseAuthData firebaseSource = FirebaseAuthData();
|
||||||
|
|
||||||
|
locator.registerLazySingleton(() => NavigationService());
|
||||||
|
locator.registerLazySingleton(() => DialogService());
|
||||||
|
locator.registerLazySingleton(() => UserAuthViewModel(firebaseSource));
|
||||||
|
locator.registerLazySingleton(() => LoginViewModel(firebaseSource));
|
||||||
|
}
|
||||||
336
lib/login/LoginScreen.dart
Normal file
336
lib/login/LoginScreen.dart
Normal file
@@ -0,0 +1,336 @@
|
|||||||
|
import 'package:days_left/base/BaseModel.dart';
|
||||||
|
import 'package:days_left/base/BaseStatelessWidget.dart';
|
||||||
|
import 'package:days_left/login/forgot_password_6.dart';
|
||||||
|
import 'package:days_left/login/signup_screen_6.dart';
|
||||||
|
import 'package:days_left/login/values/values.dart';
|
||||||
|
import 'package:days_left/login/widgets/custom_button.dart';
|
||||||
|
import 'package:days_left/login/widgets/custom_divider.dart';
|
||||||
|
import 'package:days_left/login/widgets/custom_text_form_field.dart';
|
||||||
|
import 'package:days_left/login/widgets/spaces.dart';
|
||||||
|
import 'package:days_left/viewmodels/LoginViewModel.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../locator.dart';
|
||||||
|
|
||||||
|
class LoginScreen extends BaseStatelessWidget {
|
||||||
|
@override
|
||||||
|
BaseModel getBaseModel() {
|
||||||
|
final LoginViewModel _userAuthViewModel = locator<LoginViewModel>();
|
||||||
|
return _userAuthViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget displayWidget(context, model, child) {
|
||||||
|
ThemeData theme = Theme.of(context);
|
||||||
|
var heightOfScreen = MediaQuery.of(context).size.height;
|
||||||
|
var widthOfScreen = MediaQuery.of(context).size.width;
|
||||||
|
return Scaffold(
|
||||||
|
body: Container(
|
||||||
|
child: Stack(
|
||||||
|
children: <Widget>[
|
||||||
|
_buildHeader(context),
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.only(top: heightOfScreen * 0.2),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.white,
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(Sizes.RADIUS_24),
|
||||||
|
topRight: Radius.circular(Sizes.RADIUS_24),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: ListView(
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
margin:
|
||||||
|
EdgeInsets.symmetric(horizontal: widthOfScreen * 0.1),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
StringConst.LOG_IN,
|
||||||
|
style: theme.textTheme.headline4.copyWith(
|
||||||
|
color: AppColors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SpaceH8(),
|
||||||
|
CustomDivider(
|
||||||
|
color: AppColors.violetShade2,
|
||||||
|
height: Sizes.HEIGHT_3,
|
||||||
|
width: Sizes.WIDTH_40,
|
||||||
|
),
|
||||||
|
SpaceH20(),
|
||||||
|
Text(
|
||||||
|
StringConst.LOGIN_MSG,
|
||||||
|
style: theme.textTheme.bodyText1.copyWith(
|
||||||
|
color: AppColors.greyShade8,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
fontSize: Sizes.TEXT_SIZE_14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SpaceH24(),
|
||||||
|
_buildForm(context),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Widget _buildHeader(context) {
|
||||||
|
ThemeData theme = Theme.of(context);
|
||||||
|
var heightOfScreen = MediaQuery.of(context).size.height;
|
||||||
|
var widthOfScreen = MediaQuery.of(context).size.width;
|
||||||
|
return Stack(
|
||||||
|
children: <Widget>[
|
||||||
|
Image.asset(
|
||||||
|
ImagePath.SPLASH_1,
|
||||||
|
height: heightOfScreen * 0.3,
|
||||||
|
width: widthOfScreen,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: heightOfScreen * 0.3,
|
||||||
|
width: widthOfScreen,
|
||||||
|
decoration: BoxDecoration(gradient: Gradients.headerOverlayGradient),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.only(
|
||||||
|
top: heightOfScreen * 0.075,
|
||||||
|
left: widthOfScreen * 0.1,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
StringConst.APP_NAME,
|
||||||
|
style: theme.textTheme.headline4.copyWith(
|
||||||
|
color: AppColors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildForm(context) {
|
||||||
|
ThemeData theme = Theme.of(context);
|
||||||
|
var heightOfScreen = MediaQuery.of(context).size.height;
|
||||||
|
var widthOfScreen = MediaQuery.of(context).size.width;
|
||||||
|
return Column(
|
||||||
|
children: <Widget>[
|
||||||
|
CustomTextFormField(
|
||||||
|
textInputType: TextInputType.text,
|
||||||
|
hintTextStyle: Styles.customTextStyle(color: AppColors.greyShade8),
|
||||||
|
textStyle: Styles.customTextStyle(color: AppColors.greyShade8),
|
||||||
|
labelText: StringConst.EMAIL,
|
||||||
|
labelStyle: theme.textTheme.subtitle1.copyWith(
|
||||||
|
color: AppColors.violetShade2,
|
||||||
|
),
|
||||||
|
hasSuffixIcon: true,
|
||||||
|
suffixIcon: Icon(
|
||||||
|
Icons.mail,
|
||||||
|
color: AppColors.greyShade8,
|
||||||
|
),
|
||||||
|
border:
|
||||||
|
Borders.customOutlineInputBorder(borderRadius: Sizes.RADIUS_4),
|
||||||
|
enabledBorder:
|
||||||
|
Borders.customOutlineInputBorder(borderRadius: Sizes.RADIUS_4),
|
||||||
|
focusedBorder: Borders.customOutlineInputBorder(
|
||||||
|
borderRadius: Sizes.RADIUS_4,
|
||||||
|
color: AppColors.violetShade2,
|
||||||
|
width: Sizes.WIDTH_2,
|
||||||
|
),
|
||||||
|
hintText: StringConst.EMAIL,
|
||||||
|
),
|
||||||
|
SpaceH20(),
|
||||||
|
CustomTextFormField(
|
||||||
|
textInputType: TextInputType.text,
|
||||||
|
hintTextStyle: Styles.customTextStyle(
|
||||||
|
color: AppColors.greyShade8,
|
||||||
|
),
|
||||||
|
textStyle: Styles.customTextStyle(color: AppColors.greyShade8),
|
||||||
|
labelText: StringConst.PASSWORD,
|
||||||
|
labelStyle: theme.textTheme.subtitle1.copyWith(
|
||||||
|
color: AppColors.violetShade2,
|
||||||
|
),
|
||||||
|
hintText: StringConst.PASSWORD_HINT_TEXT,
|
||||||
|
hasSuffixIcon: true,
|
||||||
|
suffixIcon: Icon(
|
||||||
|
Icons.lock,
|
||||||
|
color: AppColors.greyShade8,
|
||||||
|
),
|
||||||
|
border:
|
||||||
|
Borders.customOutlineInputBorder(borderRadius: Sizes.RADIUS_4),
|
||||||
|
enabledBorder:
|
||||||
|
Borders.customOutlineInputBorder(borderRadius: Sizes.RADIUS_4),
|
||||||
|
focusedBorder: Borders.customOutlineInputBorder(
|
||||||
|
borderRadius: Sizes.RADIUS_4,
|
||||||
|
color: AppColors.violetShade2,
|
||||||
|
width: Sizes.WIDTH_2,
|
||||||
|
),
|
||||||
|
obscured: true,
|
||||||
|
),
|
||||||
|
SpaceH16(),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () => Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => ForgotPasswordScreen6(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
StringConst.FORGOT_PASSWORD,
|
||||||
|
style: theme.textTheme.subtitle1.copyWith(
|
||||||
|
color: AppColors.black,
|
||||||
|
fontSize: Sizes.TEXT_SIZE_14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SpaceH24(),
|
||||||
|
CustomButton(
|
||||||
|
title: StringConst.LOG_IN,
|
||||||
|
color: AppColors.violetShade2,
|
||||||
|
borderRadius: Sizes.ELEVATION_4,
|
||||||
|
textStyle: theme.textTheme.button.copyWith(
|
||||||
|
color: AppColors.white,
|
||||||
|
fontSize: Sizes.TEXT_SIZE_16,
|
||||||
|
),
|
||||||
|
onPressed: () {},
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: heightOfScreen * 0.03,
|
||||||
|
),
|
||||||
|
_buildSeparator(context),
|
||||||
|
SizedBox(
|
||||||
|
height: heightOfScreen * 0.03,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
child: CustomButton(
|
||||||
|
title: StringConst.FACEBOOK,
|
||||||
|
textStyle: theme.textTheme.button
|
||||||
|
.copyWith(color: AppColors.greyShade8),
|
||||||
|
hasIcon: true,
|
||||||
|
color: AppColors.white,
|
||||||
|
elevation: Sizes.ELEVATION_0,
|
||||||
|
borderRadius: Sizes.ELEVATION_4,
|
||||||
|
borderSide: Borders.customBorder(color: AppColors.grey),
|
||||||
|
icon: Image.asset(
|
||||||
|
ImagePath.FACEBOOK,
|
||||||
|
height: Sizes.HEIGHT_24,
|
||||||
|
width: Sizes.WIDTH_24,
|
||||||
|
),
|
||||||
|
onPressed: () {},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: widthOfScreen * 0.1),
|
||||||
|
Expanded(
|
||||||
|
child: CustomButton(
|
||||||
|
title: StringConst.GOOGLE,
|
||||||
|
hasIcon: true,
|
||||||
|
color: AppColors.white,
|
||||||
|
elevation: Sizes.ELEVATION_0,
|
||||||
|
borderRadius: Sizes.ELEVATION_4,
|
||||||
|
borderSide: Borders.customBorder(color: AppColors.grey),
|
||||||
|
textStyle: theme.textTheme.button
|
||||||
|
.copyWith(color: AppColors.greyShade8),
|
||||||
|
icon: Image.asset(
|
||||||
|
ImagePath.GOOGLE,
|
||||||
|
height: Sizes.HEIGHT_24,
|
||||||
|
width: Sizes.WIDTH_24,
|
||||||
|
),
|
||||||
|
onPressed: () {},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: heightOfScreen * 0.08,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
StringConst.DONT_HAVE_AN_ACCOUNT,
|
||||||
|
style: theme.textTheme.bodyText1.copyWith(
|
||||||
|
color: AppColors.black,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
fontSize: Sizes.TEXT_SIZE_14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SpaceW4(),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () => Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => SignUpScreen6(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
StringConst.SIGN_UP,
|
||||||
|
style: theme.textTheme.headline4.copyWith(
|
||||||
|
color: AppColors.orangeShade5,
|
||||||
|
fontSize: Sizes.TEXT_SIZE_14,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SpaceH2(),
|
||||||
|
CustomDivider(
|
||||||
|
color: AppColors.orangeShade5,
|
||||||
|
height: Sizes.HEIGHT_2,
|
||||||
|
width: Sizes.WIDTH_50,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SpaceH20(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildSeparator(BuildContext context) {
|
||||||
|
var textTheme = Theme.of(context).textTheme;
|
||||||
|
var widthOfScreen = MediaQuery.of(context).size.width;
|
||||||
|
return Container(
|
||||||
|
margin: const EdgeInsets.symmetric(horizontal: Sizes.MARGIN_16),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
CustomDivider(
|
||||||
|
color: Colors.grey[300],
|
||||||
|
width: widthOfScreen * 0.15,
|
||||||
|
height: Sizes.HEIGHT_2,
|
||||||
|
),
|
||||||
|
SpaceW16(),
|
||||||
|
Text(
|
||||||
|
StringConst.OR,
|
||||||
|
style: textTheme.subtitle1.copyWith(
|
||||||
|
color: AppColors.greyShade8,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SpaceW16(),
|
||||||
|
CustomDivider(
|
||||||
|
color: Colors.grey[300],
|
||||||
|
width: widthOfScreen * 0.15,
|
||||||
|
height: Sizes.HEIGHT_2,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
120
lib/main.dart
120
lib/main.dart
@@ -1,113 +1,39 @@
|
|||||||
|
import 'package:days_left/login/LoginScreen.dart';
|
||||||
|
import 'package:days_left/screens/OverviewScreen.dart';
|
||||||
|
import 'package:days_left/services/DialogService.dart';
|
||||||
|
import 'package:days_left/services/NavigationService.dart';
|
||||||
|
import 'package:days_left/viewmodels/UserAuthViewModel.dart';
|
||||||
|
import 'package:days_left/widgets/router.dart';
|
||||||
|
import 'package:firebase_core/firebase_core.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'locator.dart';
|
||||||
|
import 'managers/DialogManager.dart';
|
||||||
|
|
||||||
void main() {
|
void main() async {
|
||||||
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
await Firebase.initializeApp();
|
||||||
|
setupLocator();
|
||||||
runApp(MyApp());
|
runApp(MyApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
// This widget is the root of your application.
|
final UserAuthViewModel _userAuthViewModel = locator<UserAuthViewModel>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
title: 'Flutter Demo',
|
title: 'Flutter Demo',
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
// This is the theme of your application.
|
|
||||||
//
|
|
||||||
// Try running your application with "flutter run". You'll see the
|
|
||||||
// application has a blue toolbar. Then, without quitting the app, try
|
|
||||||
// changing the primarySwatch below to Colors.green and then invoke
|
|
||||||
// "hot reload" (press "r" in the console where you ran "flutter run",
|
|
||||||
// or simply save your changes to "hot reload" in a Flutter IDE).
|
|
||||||
// Notice that the counter didn't reset back to zero; the application
|
|
||||||
// is not restarted.
|
|
||||||
primarySwatch: Colors.blue,
|
primarySwatch: Colors.blue,
|
||||||
),
|
),
|
||||||
home: MyHomePage(title: 'Flutter Demo Home Page'),
|
home: _userAuthViewModel.loggedIn ? OverviewScreen() : LoginScreen(),
|
||||||
);
|
onGenerateRoute: generateRoute,
|
||||||
}
|
builder: (context, child) => Navigator(
|
||||||
}
|
key: locator<DialogService>().dialogNavigationKey,
|
||||||
|
onGenerateRoute: (settings) => MaterialPageRoute(
|
||||||
class MyHomePage extends StatefulWidget {
|
builder: (context) => DialogManager(child: child)),
|
||||||
MyHomePage({Key key, this.title}) : super(key: key);
|
),
|
||||||
|
navigatorKey: locator<NavigationService>().navigationKey,
|
||||||
// This widget is the home page of your application. It is stateful, meaning
|
|
||||||
// that it has a State object (defined below) that contains fields that affect
|
|
||||||
// how it looks.
|
|
||||||
|
|
||||||
// This class is the configuration for the state. It holds the values (in this
|
|
||||||
// case the title) provided by the parent (in this case the App widget) and
|
|
||||||
// used by the build method of the State. Fields in a Widget subclass are
|
|
||||||
// always marked "final".
|
|
||||||
|
|
||||||
final String title;
|
|
||||||
|
|
||||||
@override
|
|
||||||
_MyHomePageState createState() => _MyHomePageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _MyHomePageState extends State<MyHomePage> {
|
|
||||||
int _counter = 0;
|
|
||||||
|
|
||||||
void _incrementCounter() {
|
|
||||||
setState(() {
|
|
||||||
// This call to setState tells the Flutter framework that something has
|
|
||||||
// changed in this State, which causes it to rerun the build method below
|
|
||||||
// so that the display can reflect the updated values. If we changed
|
|
||||||
// _counter without calling setState(), then the build method would not be
|
|
||||||
// called again, and so nothing would appear to happen.
|
|
||||||
_counter++;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
// This method is rerun every time setState is called, for instance as done
|
|
||||||
// by the _incrementCounter method above.
|
|
||||||
//
|
|
||||||
// The Flutter framework has been optimized to make rerunning build methods
|
|
||||||
// fast, so that you can just rebuild anything that needs updating rather
|
|
||||||
// than having to individually change instances of widgets.
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
// Here we take the value from the MyHomePage object that was created by
|
|
||||||
// the App.build method, and use it to set our appbar title.
|
|
||||||
title: Text(widget.title),
|
|
||||||
),
|
|
||||||
body: Center(
|
|
||||||
// Center is a layout widget. It takes a single child and positions it
|
|
||||||
// in the middle of the parent.
|
|
||||||
child: Column(
|
|
||||||
// Column is also a layout widget. It takes a list of children and
|
|
||||||
// arranges them vertically. By default, it sizes itself to fit its
|
|
||||||
// children horizontally, and tries to be as tall as its parent.
|
|
||||||
//
|
|
||||||
// Invoke "debug painting" (press "p" in the console, choose the
|
|
||||||
// "Toggle Debug Paint" action from the Flutter Inspector in Android
|
|
||||||
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
|
|
||||||
// to see the wireframe for each widget.
|
|
||||||
//
|
|
||||||
// Column has various properties to control how it sizes itself and
|
|
||||||
// how it positions its children. Here we use mainAxisAlignment to
|
|
||||||
// center the children vertically; the main axis here is the vertical
|
|
||||||
// axis because Columns are vertical (the cross axis would be
|
|
||||||
// horizontal).
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
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.
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
54
lib/managers/DialogManager.dart
Normal file
54
lib/managers/DialogManager.dart
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:days_left/services/DialogService.dart';
|
||||||
|
|
||||||
|
import '../locator.dart';
|
||||||
|
import '../model/DialogModels.dart';
|
||||||
|
|
||||||
|
class DialogManager extends StatefulWidget {
|
||||||
|
final Widget child;
|
||||||
|
DialogManager({Key key, this.child}) : super(key: key);
|
||||||
|
|
||||||
|
_DialogManagerState createState() => _DialogManagerState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DialogManagerState extends State<DialogManager> {
|
||||||
|
DialogService _dialogService = locator<DialogService>();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_dialogService.registerDialogListener(_showDialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return widget.child;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showDialog(DialogRequest request) {
|
||||||
|
var isConfirmationDialog = request.cancelTitle != null;
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
title: Text(request.title),
|
||||||
|
content: Text(request.description),
|
||||||
|
actions: <Widget>[
|
||||||
|
if (isConfirmationDialog)
|
||||||
|
FlatButton(
|
||||||
|
child: Text(request.cancelTitle),
|
||||||
|
onPressed: () {
|
||||||
|
_dialogService
|
||||||
|
.dialogComplete(DialogResponse(confirmed: false));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
FlatButton(
|
||||||
|
child: Text(request.buttonTitle),
|
||||||
|
onPressed: () {
|
||||||
|
_dialogService
|
||||||
|
.dialogComplete(DialogResponse(confirmed: true));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
26
lib/model/DialogModels.dart
Normal file
26
lib/model/DialogModels.dart
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
|
class DialogRequest{
|
||||||
|
final String title;
|
||||||
|
final String description;
|
||||||
|
final String buttonTitle;
|
||||||
|
final String cancelTitle;
|
||||||
|
|
||||||
|
DialogRequest(
|
||||||
|
{@required this.title,
|
||||||
|
@required this.description,
|
||||||
|
@required this.buttonTitle,
|
||||||
|
this.cancelTitle});
|
||||||
|
}
|
||||||
|
|
||||||
|
class DialogResponse {
|
||||||
|
final String fieldOne;
|
||||||
|
final String fieldTwo;
|
||||||
|
final bool confirmed;
|
||||||
|
|
||||||
|
DialogResponse({
|
||||||
|
this.fieldOne,
|
||||||
|
this.fieldTwo,
|
||||||
|
this.confirmed,
|
||||||
|
});
|
||||||
|
}
|
||||||
26
lib/model/UserProfileDetails.dart
Normal file
26
lib/model/UserProfileDetails.dart
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
class UserProfileDetails {
|
||||||
|
final String name;
|
||||||
|
final String dob;
|
||||||
|
final String postcode;
|
||||||
|
final String email;
|
||||||
|
final String phone;
|
||||||
|
final String sex;
|
||||||
|
|
||||||
|
UserProfileDetails(
|
||||||
|
this.name,
|
||||||
|
this.dob,
|
||||||
|
this.postcode,
|
||||||
|
this.email,
|
||||||
|
this.phone,
|
||||||
|
this.sex
|
||||||
|
);
|
||||||
|
|
||||||
|
UserProfileDetails.fromSnapshot(Map<dynamic, dynamic> snapshot) :
|
||||||
|
name = snapshot["name"],
|
||||||
|
dob = snapshot["dob"],
|
||||||
|
postcode = snapshot["postcode"],
|
||||||
|
email = snapshot["email"],
|
||||||
|
phone = snapshot["phone"],
|
||||||
|
sex = snapshot["sex"];
|
||||||
|
}
|
||||||
8
lib/screens/OverviewScreen.dart
Normal file
8
lib/screens/OverviewScreen.dart
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
|
class OverviewScreen extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
}
|
||||||
54
lib/services/DialogService.dart
Normal file
54
lib/services/DialogService.dart
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:days_left/model/DialogModels.dart';
|
||||||
|
|
||||||
|
class DialogService {
|
||||||
|
GlobalKey<NavigatorState> _dialogNavigationKey = GlobalKey<NavigatorState>();
|
||||||
|
Function(DialogRequest) _showDialogListener;
|
||||||
|
Completer<DialogResponse> _dialogCompleter;
|
||||||
|
|
||||||
|
GlobalKey<NavigatorState> get dialogNavigationKey => _dialogNavigationKey;
|
||||||
|
|
||||||
|
/// Registers a callback function. Typically to show the dialog
|
||||||
|
void registerDialogListener(Function(DialogRequest) showDialogListener) {
|
||||||
|
_showDialogListener = showDialogListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calls the dialog listener and returns a Future that will wait for dialogComplete.
|
||||||
|
Future<DialogResponse> showDialog({
|
||||||
|
String title,
|
||||||
|
String description,
|
||||||
|
String buttonTitle = 'Ok',
|
||||||
|
}) {
|
||||||
|
_dialogCompleter = Completer<DialogResponse>();
|
||||||
|
_showDialogListener(DialogRequest(
|
||||||
|
title: title,
|
||||||
|
description: description,
|
||||||
|
buttonTitle: buttonTitle,
|
||||||
|
));
|
||||||
|
return _dialogCompleter.future;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shows a confirmation dialog
|
||||||
|
Future<DialogResponse> showConfirmationDialog(
|
||||||
|
{String title,
|
||||||
|
String description,
|
||||||
|
String confirmationTitle = 'Ok',
|
||||||
|
String cancelTitle = 'Cancel'}) {
|
||||||
|
_dialogCompleter = Completer<DialogResponse>();
|
||||||
|
_showDialogListener(DialogRequest(
|
||||||
|
title: title,
|
||||||
|
description: description,
|
||||||
|
buttonTitle: confirmationTitle,
|
||||||
|
cancelTitle: cancelTitle));
|
||||||
|
return _dialogCompleter.future;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Completes the _dialogCompleter to resume the Future's execution call
|
||||||
|
void dialogComplete(DialogResponse response) {
|
||||||
|
_dialogNavigationKey.currentState.pop();
|
||||||
|
_dialogCompleter.complete(response);
|
||||||
|
_dialogCompleter = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
21
lib/services/NavigationService.dart
Normal file
21
lib/services/NavigationService.dart
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class NavigationService {
|
||||||
|
GlobalKey<NavigatorState> _navigationKey = GlobalKey<NavigatorState>();
|
||||||
|
|
||||||
|
GlobalKey<NavigatorState> get navigationKey => _navigationKey;
|
||||||
|
|
||||||
|
void pop() {
|
||||||
|
return _navigationKey.currentState.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<dynamic> navigateTo(String routeName, {dynamic arguments}) {
|
||||||
|
return _navigationKey.currentState
|
||||||
|
.pushNamed(routeName, arguments: arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<dynamic> navigateToAndClearStack(String routeName, {dynamic arguments}) {
|
||||||
|
return _navigationKey.currentState
|
||||||
|
.pushNamedAndRemoveUntil(routeName, (r) => false, arguments: arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
14
lib/viewmodels/LoginViewModel.dart
Normal file
14
lib/viewmodels/LoginViewModel.dart
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import 'package:days_left/data/FirebaseAuthData.dart';
|
||||||
|
import '../base/BaseModel.dart';
|
||||||
|
|
||||||
|
class LoginViewModel extends BaseModel {
|
||||||
|
FirebaseAuthData _firebaseAuthData;
|
||||||
|
LoginViewModel(this._firebaseAuthData);
|
||||||
|
|
||||||
|
void tryLogin(String email, String password) {
|
||||||
|
// Todo: validate username & password
|
||||||
|
handleFuture(_firebaseAuthData.signIn(email, password));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
16
lib/viewmodels/UserAuthViewModel.dart
Normal file
16
lib/viewmodels/UserAuthViewModel.dart
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import 'package:days_left/data/FirebaseAuthData.dart';
|
||||||
|
import '../base/BaseModel.dart';
|
||||||
|
|
||||||
|
class UserAuthViewModel extends BaseModel {
|
||||||
|
bool _loggedIn = false;
|
||||||
|
bool get loggedIn => _loggedIn;
|
||||||
|
|
||||||
|
FirebaseAuthData _firebaseAuthData;
|
||||||
|
UserAuthViewModel(this._firebaseAuthData){
|
||||||
|
_firebaseAuthData.firebaseAuth.authStateChanges().listen((event) {
|
||||||
|
_loggedIn = event != null;
|
||||||
|
notifyListeners();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
23
lib/widgets/ButtonWidget.dart
Normal file
23
lib/widgets/ButtonWidget.dart
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class ButtonWidget extends StatelessWidget{
|
||||||
|
final String label;
|
||||||
|
final Function onPressed;
|
||||||
|
|
||||||
|
ButtonWidget(this.label, {this.onPressed});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
margin: EdgeInsets.only(top: 20, bottom: 12),
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: onPressed,
|
||||||
|
child: Text(label),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
74
lib/widgets/CodeEnterWidget.dart
Normal file
74
lib/widgets/CodeEnterWidget.dart
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
class CodeEnterWidget extends StatelessWidget {
|
||||||
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
final GlobalKey<ScaffoldState> scaffoldPageOne;
|
||||||
|
|
||||||
|
CodeEnterWidget({this.scaffoldPageOne});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: Center(
|
||||||
|
child: Form(
|
||||||
|
key: _formKey,
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.grey.withOpacity(0.5),
|
||||||
|
spreadRadius: 5,
|
||||||
|
blurRadius: 7,
|
||||||
|
offset: Offset(0, 3), // changes position of shadow
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
margin: EdgeInsets.all(20.0),
|
||||||
|
padding: EdgeInsets.all(12.0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
child: Text(
|
||||||
|
"Sign in with your phone number below.",
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
color: Colors.blue,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
padding: EdgeInsets.all(20.0),
|
||||||
|
),
|
||||||
|
TextFormField(
|
||||||
|
keyboardType: TextInputType.phone,
|
||||||
|
validator: (value) {
|
||||||
|
if (value.isEmpty) {
|
||||||
|
return 'Enter the code sent to you';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.only(top: 20, bottom: 12),
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
if (_formKey.currentState.validate()) {
|
||||||
|
scaffoldPageOne.currentState.showSnackBar(
|
||||||
|
SnackBar(content: Text('Processing Data')));
|
||||||
|
}
|
||||||
|
Timer(Duration(seconds: 2), () {
|
||||||
|
// Todo: change body
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Text('Submit'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
))),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
85
lib/widgets/DisplayUserDetails.dart
Normal file
85
lib/widgets/DisplayUserDetails.dart
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:days_left/constants/constants.dart';
|
||||||
|
import 'package:days_left/model/UserProfileDetails.dart';
|
||||||
|
import 'package:days_left/services/NavigationService.dart';
|
||||||
|
|
||||||
|
import '../locator.dart';
|
||||||
|
import 'TextDetailWidget.dart';
|
||||||
|
|
||||||
|
class DisplayUserDetails extends StatelessWidget {
|
||||||
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
final NavigationService _navigationService = locator<NavigationService>();
|
||||||
|
|
||||||
|
final UserProfileDetails userDetails;
|
||||||
|
final Function callback;
|
||||||
|
|
||||||
|
DisplayUserDetails(this.userDetails, this.callback);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Center(
|
||||||
|
child: Form(
|
||||||
|
key: _formKey,
|
||||||
|
child: Container(
|
||||||
|
width: 400,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.grey.withOpacity(0.5),
|
||||||
|
spreadRadius: 5,
|
||||||
|
blurRadius: 7,
|
||||||
|
offset: Offset(0, 3), // changes position of shadow
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
margin: EdgeInsets.all(20.0),
|
||||||
|
padding: EdgeInsets.all(12.0),
|
||||||
|
child: getInnerWidget(context),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget getInnerWidget(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
child: Text(
|
||||||
|
"User Profile",
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
color: Colors.blue,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
padding: EdgeInsets.all(20.0),
|
||||||
|
),
|
||||||
|
_getInnerWidgetList(),
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.only(top: 20, bottom: 12),
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
_navigationService.navigateTo(UpdateDetailsViewRoute,
|
||||||
|
arguments: userDetails);
|
||||||
|
},
|
||||||
|
child: Text('Update'),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _getInnerWidgetList() {
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
TextDetailWidget("Name", userDetails?.name ?? "n/a"),
|
||||||
|
TextDetailWidget("D.O.B", userDetails?.dob ?? "n/a"),
|
||||||
|
TextDetailWidget("Email", userDetails?.email ?? "n/a"),
|
||||||
|
TextDetailWidget("Phone no.", userDetails?.phone ?? "n/a"),
|
||||||
|
TextDetailWidget("Sex", userDetails?.sex ?? "n/a"),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
61
lib/widgets/LoaderWidget.dart
Normal file
61
lib/widgets/LoaderWidget.dart
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class LoaderWidget extends StatefulWidget {
|
||||||
|
|
||||||
|
final Widget body;
|
||||||
|
LoaderWidget({this.body, Key key}): super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
LoaderWidgetState createState() => LoaderWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class LoaderWidgetState extends State<LoaderWidget> {
|
||||||
|
bool _status = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Center(
|
||||||
|
child: _status ? Center(child: CircularProgressIndicator())
|
||||||
|
: Center(
|
||||||
|
child: widget.body,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void changeState(){
|
||||||
|
setState(() {
|
||||||
|
_status = !_status;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class LoaderStatelessWidget extends StatelessWidget{
|
||||||
|
final loaderKey = GlobalKey<LoaderWidgetState>();
|
||||||
|
|
||||||
|
void changeState(){
|
||||||
|
loaderKey.currentState.changeState();
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget LoaderWidgeted({Widget body}){
|
||||||
|
return LoaderWidget(body: body, key: loaderKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class LoaderStatefulWidget<T extends StatefulWidget> extends State<T>{
|
||||||
|
final loaderKey = GlobalKey<LoaderWidgetState>();
|
||||||
|
|
||||||
|
void changeState(){
|
||||||
|
loaderKey.currentState.changeState();
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget LoaderWidgeted(Widget body, Key key){
|
||||||
|
return LoaderWidget(body: body, key: key);
|
||||||
|
}
|
||||||
|
}
|
||||||
26
lib/widgets/TextDetailWidget.dart
Normal file
26
lib/widgets/TextDetailWidget.dart
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class TextDetailWidget extends StatelessWidget {
|
||||||
|
final String labelText;
|
||||||
|
final String bodyText;
|
||||||
|
|
||||||
|
TextDetailWidget(this.labelText, this.bodyText);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
labelText,
|
||||||
|
style: TextStyle(color: Colors.blue),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
bodyText,
|
||||||
|
style: TextStyle(color: Colors.black),
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
28
lib/widgets/router.dart
Normal file
28
lib/widgets/router.dart
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import 'package:days_left/login/login_screen_6.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import '../constants/constants.dart';
|
||||||
|
|
||||||
|
|
||||||
|
Route<dynamic> generateRoute(RouteSettings settings) {
|
||||||
|
switch (settings.name) {
|
||||||
|
case LoginViewRoute:
|
||||||
|
return _getPageRoute(
|
||||||
|
routeName: settings.name,
|
||||||
|
viewToShow: LoginScreen6(),
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return MaterialPageRoute(
|
||||||
|
builder: (_) => Scaffold(
|
||||||
|
body: Center(
|
||||||
|
child: Text('No route defined for ${settings.name}')),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PageRoute _getPageRoute({String routeName, Widget viewToShow}) {
|
||||||
|
return MaterialPageRoute(
|
||||||
|
settings: RouteSettings(
|
||||||
|
name: routeName,
|
||||||
|
),
|
||||||
|
builder: (_) => viewToShow);
|
||||||
|
}
|
||||||
361
pubspec.lock
361
pubspec.lock
@@ -1,62 +1,202 @@
|
|||||||
# Generated by pub
|
# Generated by pub
|
||||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||||
packages:
|
packages:
|
||||||
|
_fe_analyzer_shared:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: _fe_analyzer_shared
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.0"
|
||||||
|
analyzer:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: analyzer
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.39.17"
|
||||||
|
args:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: args
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.6.0"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: async
|
name: async
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.0-nullsafety.1"
|
version: "2.7.0"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: boolean_selector
|
name: boolean_selector
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0-nullsafety.1"
|
version: "2.1.0"
|
||||||
|
build:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.6.2"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: characters
|
name: characters
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0-nullsafety.3"
|
version: "1.1.0"
|
||||||
charcode:
|
charcode:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: charcode
|
name: charcode
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0-nullsafety.1"
|
version: "1.3.1"
|
||||||
|
cli_util:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cli_util
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.0"
|
||||||
clock:
|
clock:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: clock
|
name: clock
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0-nullsafety.1"
|
version: "1.1.0"
|
||||||
|
cloud_firestore:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: cloud_firestore
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.0"
|
||||||
|
cloud_firestore_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cloud_firestore_platform_interface
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "5.3.0"
|
||||||
|
cloud_firestore_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cloud_firestore_web
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.0"
|
||||||
collection:
|
collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: collection
|
name: collection
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.15.0-nullsafety.3"
|
version: "1.15.0"
|
||||||
|
convert:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: convert
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.1"
|
||||||
|
crypto:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: crypto
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.5"
|
||||||
|
csslib:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: csslib
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.16.2"
|
||||||
cupertino_icons:
|
cupertino_icons:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: cupertino_icons
|
name: cupertino_icons
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.3"
|
||||||
|
dart_style:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dart_style
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.6"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: fake_async
|
name: fake_async
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0-nullsafety.1"
|
version: "1.2.0"
|
||||||
|
file:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "5.2.1"
|
||||||
|
firebase_auth:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: firebase_auth
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.1"
|
||||||
|
firebase_auth_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: firebase_auth_platform_interface
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "6.0.0"
|
||||||
|
firebase_auth_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: firebase_auth_web
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.0"
|
||||||
|
firebase_core:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: firebase_core
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.0"
|
||||||
|
firebase_core_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: firebase_core_platform_interface
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.1"
|
||||||
|
firebase_core_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: firebase_core_web
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
|
firebase_database:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: firebase_database
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "7.1.2"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -67,87 +207,268 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_web_plugins:
|
||||||
|
dependency: transitive
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
|
get:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: get
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.26.0"
|
||||||
|
get_it:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: get_it
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "6.1.1"
|
||||||
|
glob:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: glob
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.0"
|
||||||
|
html:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: html
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.14.0+4"
|
||||||
|
http_parser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http_parser
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.0"
|
||||||
|
intl:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: intl
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.17.0"
|
||||||
|
js:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: js
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.6.3"
|
||||||
|
logging:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: logging
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.1"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.10-nullsafety.1"
|
version: "0.12.10"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0-nullsafety.4"
|
version: "1.7.0"
|
||||||
|
nested:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: nested
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
|
node_interop:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: node_interop
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.1"
|
||||||
|
node_io:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: node_io
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.0"
|
||||||
|
observable_ish:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: observable_ish
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.5"
|
||||||
|
package_config:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: package_config
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.9.3"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path
|
name: path
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.0-nullsafety.1"
|
version: "1.8.0"
|
||||||
|
pedantic:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pedantic
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.11.1"
|
||||||
|
plugin_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: plugin_platform_interface
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
|
provider:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: provider
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "5.0.0"
|
||||||
|
pub_semver:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pub_semver
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.4"
|
||||||
|
sealed_class:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: sealed_class
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.0"
|
||||||
|
sealed_class_generator:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: sealed_class_generator
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.0"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.99"
|
version: "0.0.99"
|
||||||
|
source_gen:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_gen
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.9.10+2"
|
||||||
source_span:
|
source_span:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_span
|
name: source_span
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.0-nullsafety.2"
|
version: "1.8.1"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stack_trace
|
name: stack_trace
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.10.0-nullsafety.2"
|
version: "1.10.0"
|
||||||
|
stacked:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: stacked
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.9.8"
|
||||||
|
stacked_services:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: stacked_services
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.4.11"
|
||||||
stream_channel:
|
stream_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stream_channel
|
name: stream_channel
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0-nullsafety.1"
|
version: "2.1.0"
|
||||||
string_scanner:
|
string_scanner:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: string_scanner
|
name: string_scanner
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0-nullsafety.1"
|
version: "1.1.0"
|
||||||
term_glyph:
|
term_glyph:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: term_glyph
|
name: term_glyph
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0-nullsafety.1"
|
version: "1.2.0"
|
||||||
test_api:
|
test_api:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.19-nullsafety.2"
|
version: "0.4.2"
|
||||||
|
toast:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: toast
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.5"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: typed_data
|
name: typed_data
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0-nullsafety.3"
|
version: "1.3.0"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vector_math
|
name: vector_math
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0-nullsafety.3"
|
version: "2.1.0"
|
||||||
|
watcher:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: watcher
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.9.7+15"
|
||||||
|
yaml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: yaml
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.1"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.10.0-110 <=2.11.0-213.1.beta"
|
dart: ">=2.12.0 <3.0.0"
|
||||||
|
flutter: ">=1.16.0"
|
||||||
|
|||||||
16
pubspec.yaml
16
pubspec.yaml
@@ -23,15 +23,25 @@ environment:
|
|||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
|
|
||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
cupertino_icons: ^1.0.0
|
cupertino_icons: ^1.0.0
|
||||||
|
# utils
|
||||||
|
toast: ^0.1.5
|
||||||
|
sealed_class:
|
||||||
|
# stacked
|
||||||
|
stacked: ^1.6.0
|
||||||
|
stacked_services: ^0.4.3
|
||||||
|
# Firebase
|
||||||
|
firebase_core: 1.4.0
|
||||||
|
cloud_firestore: 2.4.0
|
||||||
|
firebase_auth: 3.0.1
|
||||||
|
firebase_database: 7.1.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
sealed_class_generator:
|
||||||
|
|
||||||
# For information on the generic Dart part of this file, see the
|
# For information on the generic Dart part of this file, see the
|
||||||
# following page: https://dart.dev/tools/pub/pubspec
|
# following page: https://dart.dev/tools/pub/pubspec
|
||||||
@@ -44,6 +54,8 @@ flutter:
|
|||||||
# the material Icons class.
|
# the material Icons class.
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
|
||||||
|
assets:
|
||||||
|
- assets/images/
|
||||||
# To add assets to your application, add an assets section, like this:
|
# To add assets to your application, add an assets section, like this:
|
||||||
# assets:
|
# assets:
|
||||||
# - images/a_dot_burr.jpeg
|
# - images/a_dot_burr.jpeg
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
// This is a basic Flutter widget test.
|
|
||||||
//
|
|
||||||
// To perform an interaction with a widget in your test, use the WidgetTester
|
|
||||||
// utility that Flutter provides. For example, you can send tap and scroll
|
|
||||||
// gestures. You can also use WidgetTester to find child widgets in the widget
|
|
||||||
// tree, read text, and verify that the values of widget properties are correct.
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
|
|
||||||
import 'package:days_left/main.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
|
||||||
// Build our app and trigger a frame.
|
|
||||||
await tester.pumpWidget(MyApp());
|
|
||||||
|
|
||||||
// Verify that our counter starts at 0.
|
|
||||||
expect(find.text('0'), findsOneWidget);
|
|
||||||
expect(find.text('1'), findsNothing);
|
|
||||||
|
|
||||||
// Tap the '+' icon and trigger a frame.
|
|
||||||
await tester.tap(find.byIcon(Icons.add));
|
|
||||||
await tester.pump();
|
|
||||||
|
|
||||||
// Verify that our counter has incremented.
|
|
||||||
expect(find.text('0'), findsNothing);
|
|
||||||
expect(find.text('1'), findsOneWidget);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -33,6 +33,29 @@
|
|||||||
<!-- This script installs service_worker.js to provide PWA functionality to
|
<!-- This script installs service_worker.js to provide PWA functionality to
|
||||||
application. For more information, see:
|
application. For more information, see:
|
||||||
https://developers.google.com/web/fundamentals/primers/service-workers -->
|
https://developers.google.com/web/fundamentals/primers/service-workers -->
|
||||||
|
<!-- The core Firebase JS SDK is always required and must be listed first -->
|
||||||
|
<script src="https://www.gstatic.com/firebasejs/8.6.1/firebase-app.js"></script>
|
||||||
|
<script src="https://www.gstatic.com/firebasejs/8.6.1/firebase-auth.js"></script>
|
||||||
|
<script src="https://www.gstatic.com/firebasejs/7.17.1/firebase-firestore.js"></script>
|
||||||
|
|
||||||
|
<!-- https://firebase.google.com/docs/web/setup#available-libraries -->
|
||||||
|
<script src="https://www.gstatic.com/firebasejs/8.0.0/firebase-analytics.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Your web app's Firebase configuration
|
||||||
|
var firebaseConfig = {
|
||||||
|
apiKey: "AIzaSyDZk-H3yoMupYsTt85kXS3h3GCe2F8MjmU",
|
||||||
|
authDomain: "farmr-8a496.firebaseapp.com",
|
||||||
|
databaseURL: "https://farmr-8a496.firebaseio.com",
|
||||||
|
projectId: "farmr-8a496",
|
||||||
|
storageBucket: "farmr-8a496.appspot.com",
|
||||||
|
messagingSenderId: "640643168912",
|
||||||
|
appId: "1:640643168912:web:d3a99b921e48d1dd2bb615"
|
||||||
|
};
|
||||||
|
// Initialize Firebase
|
||||||
|
firebase.initializeApp(firebaseConfig);
|
||||||
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
if ('serviceWorker' in navigator) {
|
if ('serviceWorker' in navigator) {
|
||||||
window.addEventListener('flutter-first-frame', function () {
|
window.addEventListener('flutter-first-frame', function () {
|
||||||
|
|||||||
Reference in New Issue
Block a user