login navigate

4.4
Serik.Uvaissov 2020-05-21 16:12:32 +06:00
parent 30db638877
commit 46302aed18
20 changed files with 565 additions and 67 deletions

View File

@ -1,19 +1,22 @@
import '../core/services/ApiService.dart';
import '../core/services/ApiService.dart';
import '../core/services/authentication_service.dart';
import '../core/logger.dart'; import '../core/logger.dart';
import '../core/services/navigator_service.dart'; import '../core/services/navigator_service.dart';
import 'package:get_it/get_it.dart'; import 'package:get_it/get_it.dart';
import 'package:logger/logger.dart'; import 'package:logger/logger.dart';
GetIt locator = GetIt.instance; GetIt locator = GetIt.I;
class LocatorInjector { class LocatorInjector {
static Logger _log = getLogger('LocatorInjector'); static Logger _log = getLogger('LocatorInjector');
static Future<void> setupLocator() async { static Future<void> setupLocator() async {
_log.d('Initializing Navigator Service');
locator.registerLazySingleton(() => NavigatorService());
_log.d('Initializing Api Service'); _log.d('Initializing Api Service');
locator.registerLazySingleton(() => ApiService()); locator.registerLazySingleton<ApiService>(() => ApiService());
_log.d('Initializing Navigator Service');
locator.registerLazySingleton<NavigatorService>(() => NavigatorService());
} }
} }

View File

@ -0,0 +1,16 @@
class Session {
String token;
int appCompanyId;
int kassaId;
int userId;
String message;
Session();
Session.fromData(String token ,Map<String, dynamic> data)
: token = token,
appCompanyId = data['app_company_id'],
userId = data['user_id'],
message = data['message'],
kassaId = data['kassa_id'];
}

View File

@ -1,23 +1,20 @@
class User { class User {
final String id; final String token;
final String fullName; final String fullName;
final String email; final String email;
final String userRole;
User({this.id, this.fullName, this.email, this.userRole}); User({this.token, this.fullName, this.email});
User.fromData(Map<String, dynamic> data) User.fromData(Map<String, dynamic> data)
: id = data['id'], : token = data['api_token'],
fullName = data['fullName'], fullName = data['fullName'],
email = data['email'], email = data['email'];
userRole = data['userRole'];
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return { return {
'id': id, 'api_token': token,
'fullName': fullName, 'fullName': fullName,
'email': email, 'email': email,
'userRole': userRole,
}; };
} }
} }

View File

@ -1,21 +1,47 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io';
import 'package:aman_kassa_flutter/core/base/base_service.dart'; import 'package:aman_kassa_flutter/core/base/base_service.dart';
import 'package:aman_kassa_flutter/core/models/user.dart'; import 'package:aman_kassa_flutter/core/models/session.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
/// The service responsible for networking requests /// The service responsible for networking requests
class ApiService extends BaseService { class ApiService extends BaseService {
static const endpoint = 'https://jsonplaceholder.typicode.com'; static const endpoint = 'https://kassa-test.aman.com.kz/ru/api/v2';
var client = new http.Client(); var client = new http.Client();
Future<User> getUserProfile(int userId) async { Future<Session> isActive(String token) async {
// Get user profile for id // var map = new Map<String, dynamic>();
var response = await client.get('$endpoint/users/$userId'); // map['api_token'] = token;
// var response = await client.post(
// '$endpoint/test_auth',
// headers: {
// HttpHeaders.contentTypeHeader: "multipart/form-data",
// HttpHeaders.cacheControlHeader: "no-cache"
// },
// body: map);
// print(response.body);
// return Session.fromData(token,json.decode(response.body));
Map<String, String> requestBody = <String,String>{
'api_token':token
};
Map<String, String> headers= <String,String>{
HttpHeaders.contentTypeHeader: "multipart/form-data",
HttpHeaders.cacheControlHeader: "no-cache"
};
// Convert and return var uri = Uri.parse('$endpoint/test_auth');
return User.fromData(json.decode(response.body)); var request = http.MultipartRequest('POST', uri)
..headers.addAll(headers) //if u have headers, basic auth, token bearer... Else remove line
..fields.addAll(requestBody);
var response = await request.send();
final respStr = await response.stream.bytesToString();
print(respStr);
return Session.fromData(token,json.decode(respStr));
} }
// Future<List<Post>> getPostsForUser(int userId) async { // Future<List<Post>> getPostsForUser(int userId) async {

View File

@ -1,5 +1,6 @@
import 'package:aman_kassa_flutter/core/base/base_service.dart'; import 'package:aman_kassa_flutter/core/base/base_service.dart';
import 'package:aman_kassa_flutter/core/models/session.dart';
import 'package:aman_kassa_flutter/core/models/user.dart'; import 'package:aman_kassa_flutter/core/models/user.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -14,17 +15,29 @@ class AuthenticationService extends BaseService {
User _currentUser; User _currentUser;
User get currentUser => _currentUser; User get currentUser => _currentUser;
Future loginWithEmail({ Session _session;
@required String email, Session get currentSession => _session;
@required String password,
}) async { // Future loginWithEmail({
try { // @required String email,
User result = await _api.getUserProfile(123); // @required String password,
_currentUser = result; // }) async {
return result != null; // try {
} catch (e) { // User result = await _api.getUserProfile(123);
return e.message; // _currentUser = result;
// return result != null;
// } catch (e) {
// return e.message;
// }
// }
Future<bool> isUserLoggedIn(token) async {
Session session = await _api.isActive(token);
if("OK" == session.message){
_session = session;
return true;
} }
return false;
} }
// Future<bool> isUserLoggedIn() async { // Future<bool> isUserLoggedIn() async {

View File

@ -4,6 +4,19 @@ import 'package:flutter/material.dart';
class NavigatorService extends BaseService { class NavigatorService extends BaseService {
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
Future<dynamic> push(String routeName, {dynamic arguments}) {
log.i('routeName: $routeName');
return navigatorKey.currentState
.pushNamed(routeName, arguments: arguments);
}
Future<dynamic> replace(String routeName) {
log.i('routeName: $routeName');
return navigatorKey.currentState
.pushNamedAndRemoveUntil(routeName, (Route<dynamic> route) => false);
}
Future<T> navigateToPage<T>(MaterialPageRoute<T> pageRoute) async { Future<T> navigateToPage<T>(MaterialPageRoute<T> pageRoute) async {
log.i('navigateToPage: pageRoute: ${pageRoute.settings.name}'); log.i('navigateToPage: pageRoute: ${pageRoute.settings.name}');
if (navigatorKey.currentState == null) { if (navigatorKey.currentState == null) {

View File

@ -1,14 +1,19 @@
import 'package:aman_kassa_flutter/views/login/login_view.dart'; //general
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
//service & tools
import 'core/locator.dart'; import 'core/locator.dart';
import 'core/providers.dart'; import 'core/providers.dart';
import 'core/router.dart'; import 'core/router.dart';
import 'core/services/navigator_service.dart'; import 'core/services/navigator_service.dart';
import 'package:flutter/material.dart'; //pages
import 'package:provider/provider.dart'; import 'views/start_up/start_up_view.dart';
import 'views/home/home_view.dart';
//main start
void main() async { void main() async {
WidgetsFlutterBinding.ensureInitialized();
//initialize locator
await LocatorInjector.setupLocator(); await LocatorInjector.setupLocator();
runApp(MainApplication()); runApp(MainApplication());
} }
@ -20,7 +25,7 @@ class MainApplication extends StatelessWidget {
providers: ProviderInjector.providers.toList(), providers: ProviderInjector.providers.toList(),
child: MaterialApp( child: MaterialApp(
navigatorKey: locator<NavigatorService>().navigatorKey, navigatorKey: locator<NavigatorService>().navigatorKey,
home: HomeView(), home: StartUpView(), // first page
onGenerateRoute: generateRoute, onGenerateRoute: generateRoute,
), ),
); );

View File

@ -0,0 +1,14 @@
import 'package:flutter/material.dart';
const Color shadowColor = Color.fromRGBO(80, 137, 196, 0.47);
const Color cardShadowColor = Color.fromRGBO(228, 229, 231, 0.25);
const Color blueColor = Color.fromRGBO(96, 205, 255, 1);
const Color blueColorLigth = Color.fromRGBO(96, 205, 255, 0.536);
const Color redColor = Color.fromRGBO(255, 98, 96, 1);
const Color greenColor = Color.fromRGBO(59, 222, 134, 1);
const Color whiteColor = Color.fromRGBO(255, 255, 255, 1);
const Color textColor = Color.fromRGBO(107, 120, 151, 1);
const Color textColorLight = Color.fromRGBO(162, 171, 191, 1);
const Color dayColor = Color.fromRGBO(52, 72, 94, 0.536);
const Color dayColorLight = Color.fromRGBO(255, 228, 231, 1);
const Color backgroundColor = Color.fromRGBO(249, 250, 254, 1);

View File

@ -0,0 +1,32 @@
import 'package:aman_kassa_flutter/shared/app_colors.dart';
import 'package:flutter/material.dart';
// Box Decorations
BoxDecoration fieldDecortaion = BoxDecoration(
borderRadius: BorderRadius.circular(5), color: Colors.white);
BoxDecoration disabledFieldDecortaion = BoxDecoration(
borderRadius: BorderRadius.circular(5), color: Colors.grey[100]);
// Field Variables
const double fieldHeight = 55;
const double smallFieldHeight = 40;
const double inputFieldBottomMargin = 30;
const double inputFieldSmallBottomMargin = 0;
const EdgeInsets fieldPadding = const EdgeInsets.symmetric(horizontal: 15);
const EdgeInsets largeFieldPadding =
const EdgeInsets.symmetric(horizontal: 15, vertical: 15);
// Text Variables
const TextStyle buttonTitleTextStyle =
const TextStyle(fontWeight: FontWeight.w400, color: whiteColor, fontSize: 15);
const TextStyle stepTitleTextStyle =
const TextStyle(fontWeight: FontWeight.w700, color: textColor, fontSize: 15);
const TextStyle stepSubTitleTextStyle = const TextStyle(fontWeight: FontWeight.w400, color: textColor, fontSize: 12);
// Box Shadow
const BoxShadow mainShadowBox = BoxShadow(blurRadius: 16, color: shadowColor, offset: Offset(0, 5));
const BoxShadow cardShadowBox = BoxShadow(blurRadius: 23, color: cardShadowColor, offset: Offset(0, 2));

View File

@ -0,0 +1,38 @@
import 'package:flutter/material.dart';
const Widget horizontalSpaceTiny = SizedBox(width: 5.0);
const Widget horizontalSpaceSmall = SizedBox(width: 10.0);
const Widget horizontalSpaceMedium = SizedBox(width: 25.0);
const Widget verticalSpaceTiny = SizedBox(height: 5.0);
const Widget verticalSpaceSmall = SizedBox(height: 10.0);
const Widget verticalSpaceMedium = SizedBox(height: 25.0);
const Widget verticalSpaceLarge = SizedBox(height: 50.0);
const Widget verticalSpaceMassive = SizedBox(height: 120.0);
Widget spacedDivider = Column(
children: const <Widget>[
verticalSpaceMedium,
const Divider(color: Colors.blueGrey, height: 5.0),
verticalSpaceMedium,
],
);
Widget verticalSpace(double height) => SizedBox(height: height);
double screenWidth(BuildContext context) => MediaQuery.of(context).size.width;
double screenHeight(BuildContext context) => MediaQuery.of(context).size.height;
double screenHeightFraction(BuildContext context,
{int dividedBy = 1, double offsetBy = 0}) =>
(screenHeight(context) - offsetBy) / dividedBy;
double screenWidthFraction(BuildContext context,
{int dividedBy = 1, double offsetBy = 0}) =>
(screenWidth(context) - offsetBy) / dividedBy;
double halfScreenWidth(BuildContext context) =>
screenWidthFraction(context, dividedBy: 2);
double thirdScreenWidth(BuildContext context) =>
screenWidthFraction(context, dividedBy: 3);

View File

@ -10,32 +10,13 @@ class HomeView extends StatelessWidget {
return ViewModelBuilder<HomeViewModel>.reactive( return ViewModelBuilder<HomeViewModel>.reactive(
viewModelBuilder: () => HomeViewModel(), viewModelBuilder: () => HomeViewModel(),
onModelReady: (viewModel) { onModelReady: (viewModel) {
//viewModel.busy = true; viewModel.busy = true;
}, },
builder: (context, viewModel, child) { builder: (context, viewModel, child) {
return buildWaitingLogo(context, viewModel, child); return Scaffold(
body: Center(child: Text('HomeView')),
);
}); });
} }
Widget buildWaitingLogo(
BuildContext context, HomeViewModel viewModel, Widget child) =>
new Scaffold(
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(
width: 300,
height: 100,
child: Image.asset('assets/images/icon_large.png'),
),
CircularProgressIndicator(
strokeWidth: 3,
valueColor: AlwaysStoppedAnimation(
Colors.yellow[300],
),
)
],
),
));
} }

View File

@ -1,9 +1,8 @@
import 'package:aman_kassa_flutter/core/base/base_view_model.dart'; import 'package:aman_kassa_flutter/core/base/base_view_model.dart';
import 'package:aman_kassa_flutter/core/locator.dart'; import 'package:aman_kassa_flutter/core/locator.dart';
import 'package:aman_kassa_flutter/core/route_names.dart';
import 'package:aman_kassa_flutter/core/services/navigator_service.dart'; import 'package:aman_kassa_flutter/core/services/navigator_service.dart';
import 'package:aman_kassa_flutter/views/login/login_view.dart';
import 'package:flutter/material.dart';
class HomeViewModel extends BaseViewModel { class HomeViewModel extends BaseViewModel {
final NavigatorService _navigationService = locator<NavigatorService>(); final NavigatorService _navigationService = locator<NavigatorService>();
@ -19,7 +18,5 @@ class HomeViewModel extends BaseViewModel {
void increment() => this.counter += 1; void increment() => this.counter += 1;
void goToLogin() {
_navigationService.navigateToPage(MaterialPageRoute(builder: (context) => LoginView()));
}
} }

View File

@ -1,10 +1,19 @@
library login_view; library login_view;
import 'package:aman_kassa_flutter/shared/ui_helpers.dart';
import 'package:aman_kassa_flutter/widgets/fields/busy_button.dart';
import 'package:aman_kassa_flutter/widgets/fields/input_field.dart';
import 'package:aman_kassa_flutter/widgets/fields/text_link.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
import 'login_view_model.dart'; import 'login_view_model.dart';
class LoginView extends StatelessWidget { class LoginView extends StatelessWidget {
final emailController = TextEditingController();
final passwordController = TextEditingController();
final FocusNode passwordNode = new FocusNode();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
//LoginViewModel viewModel = LoginViewModel(); //LoginViewModel viewModel = LoginViewModel();
@ -15,8 +24,59 @@ class LoginView extends StatelessWidget {
}, },
builder: (context, viewModel, child) { builder: (context, viewModel, child) {
return Scaffold( return Scaffold(
body: Center(child: Text('LoginMobile')), //backgroundColor: Colors.white,
); body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 50),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
height: 150,
child: Image.asset('assets/images/logo.png'),
//child: FlutterLogo(size: 120,),
),
InputField(
placeholder: 'Электронная почта',
controller: emailController,
textInputType: TextInputType.emailAddress,
nextFocusNode: passwordNode,
),
verticalSpaceSmall,
InputField(
placeholder: 'Пароль',
password: true,
controller: passwordController,
fieldFocusNode: passwordNode,
),
verticalSpaceMedium,
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
children: [
BusyButton(
title: 'Войти',
busy: viewModel.busy,
onPressed: () {
viewModel.login(
email: emailController.text.trim(),
password: passwordController.text,
);
},
)
],
),
verticalSpaceLarge,
TextLink(
'Регистрация',
onPressed: () {
//viewModel.navigateToSignUp();
},
)
],
),
));
}); });
} }
} }

View File

@ -2,6 +2,8 @@ import 'package:aman_kassa_flutter/core/base/base_view_model.dart';
class LoginViewModel extends BaseViewModel { class LoginViewModel extends BaseViewModel {
LoginViewModel(); LoginViewModel();
void login({String email, String password}) {}
// Add ViewModel specific code here // Add ViewModel specific code here
} }

View File

@ -0,0 +1,39 @@
library home_view;
import 'package:provider/provider.dart';
import 'start_up_view_model.dart';
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
class StartUpView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ViewModelBuilder<StartUpViewModel>.reactive(
viewModelBuilder: () => StartUpViewModel(authenticationService: Provider.of(context), navigationService: Provider.of(context)),
onModelReady: (viewModel) {
viewModel.handleStartUpLogic();
},
builder: (context, viewModel, child) {
return Scaffold(
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(
width: 500,
height: 200,
child: Image.asset('assets/images/icon_large.png'),
),
CircularProgressIndicator(
strokeWidth: 3,
valueColor: AlwaysStoppedAnimation(
Colors.yellow[300],
),
)
],
),
));
});
}
}

View File

@ -0,0 +1,33 @@
import 'package:aman_kassa_flutter/core/base/base_view_model.dart';
import 'package:aman_kassa_flutter/core/route_names.dart';
import 'package:aman_kassa_flutter/core/services/authentication_service.dart';
import 'package:aman_kassa_flutter/core/services/navigator_service.dart';
import 'package:flutter/material.dart';
class StartUpViewModel extends BaseViewModel {
NavigatorService _navigationService;
AuthenticationService _authenticationService;
StartUpViewModel({
@required AuthenticationService authenticationService,
@required NavigatorService navigationService,
}) :
_authenticationService = authenticationService ,
_navigationService = navigationService;
Future handleStartUpLogic() async {
// Register for push notifications
//await _pushNotificationService.initialise();
var hasLoggedInUser = await _authenticationService.isUserLoggedIn('test');
log.i('hasLoggedInUser $hasLoggedInUser');
if (hasLoggedInUser) {
//_navigationService.navigateTo(HomeViewRoute);
_navigationService.replace(HomeViewRoute);
} else {
_navigationService.replace(LoginViewRoute);
}
}
}

View File

@ -0,0 +1,52 @@
import 'package:aman_kassa_flutter/shared/app_colors.dart';
import 'package:aman_kassa_flutter/shared/shared_styles.dart';
import 'package:flutter/material.dart';
/// A button that shows a busy indicator in place of title
class BusyButton extends StatefulWidget {
final bool busy;
final String title;
final Function onPressed;
final bool enabled;
const BusyButton(
{@required this.title,
this.busy = false,
@required this.onPressed,
this.enabled = true});
@override
_BusyButtonState createState() => _BusyButtonState();
}
class _BusyButtonState extends State<BusyButton> {
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: widget.onPressed,
child: InkWell(
child: AnimatedContainer(
height: widget.busy ? 40 : null,
width: widget.busy ? 40 : null,
duration: const Duration(milliseconds: 300),
alignment: Alignment.center,
padding: EdgeInsets.symmetric(
horizontal: widget.busy ? 10 : 25,
vertical: widget.busy ? 10 : 15),
decoration: BoxDecoration(
color: widget.enabled ? blueColor : blueColorLigth,
borderRadius: BorderRadius.circular(7),
boxShadow: [mainShadowBox]
),
child: !widget.busy
? Text(
widget.title,
style: buttonTitleTextStyle,
)
: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(Colors.white)),
),
),
);
}
}

View File

@ -0,0 +1,135 @@
import 'package:aman_kassa_flutter/shared/app_colors.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:aman_kassa_flutter/shared/shared_styles.dart';
import 'package:aman_kassa_flutter/shared/ui_helpers.dart';
import 'note_text.dart';
class InputField extends StatefulWidget {
final TextEditingController controller;
final TextInputType textInputType;
final bool password;
final bool isReadOnly;
final String placeholder;
final String validationMessage;
final Function enterPressed;
final bool smallVersion;
final FocusNode fieldFocusNode;
final FocusNode nextFocusNode;
final TextInputAction textInputAction;
final bool multiline;
final String additionalNote;
final Function(String) onChanged;
final TextInputFormatter formatter;
final String initialValue;
final String labelText;
InputField(
{
this.controller,
@required this.placeholder,
this.enterPressed,
this.fieldFocusNode,
this.nextFocusNode,
this.additionalNote,
this.onChanged,
this.formatter,
this.initialValue,
this.validationMessage,
this.textInputAction = TextInputAction.next,
this.textInputType = TextInputType.text,
this.password = false,
this.isReadOnly = false,
this.multiline = false,
this.smallVersion = false, this.labelText});
@override
_InputFieldState createState() => _InputFieldState();
}
class _InputFieldState extends State<InputField> {
bool isPassword;
double fieldHeight = 55;
@override
void initState() {
super.initState();
isPassword = widget.password;
}
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
if (widget.labelText != null) NoteText(widget.labelText),
Container(
//height: widget.smallVersion ? 40 : fieldHeight,
constraints: BoxConstraints(minHeight: widget.smallVersion ? 40 : fieldHeight),
alignment: Alignment.centerLeft,
padding: fieldPadding,
decoration:
widget.isReadOnly ? disabledFieldDecortaion : fieldDecortaion,
child: Row(
children: <Widget>[
Expanded(
child: TextFormField(
style: TextStyle( color: textColor ),
controller: widget.controller,
keyboardType: widget.textInputType,
focusNode: widget.fieldFocusNode,
textInputAction: widget.textInputAction,
maxLines: widget.multiline ? null : 1,
onChanged: widget.onChanged,
initialValue: widget.initialValue,
inputFormatters:
widget.formatter != null ? [widget.formatter] : null,
onEditingComplete: () {
if (widget.enterPressed != null) {
FocusScope.of(context).requestFocus(FocusNode());
widget.enterPressed();
}
},
onFieldSubmitted: (value) {
if (widget.nextFocusNode != null) {
widget.nextFocusNode.requestFocus();
}
},
obscureText: isPassword,
readOnly: widget.isReadOnly,
decoration: InputDecoration.collapsed(
hintText: widget.placeholder,
hintStyle:
TextStyle(fontSize: widget.smallVersion ? 12 : 15, color: textColorLight)),
),
),
GestureDetector(
onTap: () => setState(() {
isPassword = !isPassword;
}),
child: widget.password
? Container(
width: fieldHeight,
height: fieldHeight,
alignment: Alignment.center,
child: Icon(isPassword
? Icons.visibility
: Icons.visibility_off, color: textColor))
: Container(),
),
],
),
),
if (widget.validationMessage != null)
NoteText(
widget.validationMessage,
color: Colors.red,
),
if (widget.additionalNote != null) verticalSpace(5),
if (widget.additionalNote != null) NoteText(widget.additionalNote),
verticalSpaceSmall
],
);
}
}

View File

@ -0,0 +1,23 @@
import 'package:aman_kassa_flutter/shared/app_colors.dart';
import 'package:flutter/material.dart';
class NoteText extends StatelessWidget {
final String text;
final TextAlign textAlign;
final Color color;
final double fontSize;
const NoteText(this.text, {this.textAlign, this.color, this.fontSize});
@override
Widget build(BuildContext context) {
return Text(
text,
textAlign: textAlign,
style: TextStyle(
fontSize: fontSize ?? 12,
fontWeight: FontWeight.normal,
color: color ?? dayColor,
),
);
}
}

View File

@ -0,0 +1,19 @@
import 'package:aman_kassa_flutter/shared/app_colors.dart';
import 'package:flutter/material.dart';
class TextLink extends StatelessWidget {
final String text;
final Function onPressed;
const TextLink(this.text, {this.onPressed});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onPressed,
child: Text(
text,
style: TextStyle(fontWeight: FontWeight.w700, fontSize: 14, color: textColor),
),
);
}
}