diff --git a/lib/extensions/text_extensions.dart b/lib/extensions/text_extensions.dart new file mode 100644 index 00000000..c426f8b5 --- /dev/null +++ b/lib/extensions/text_extensions.dart @@ -0,0 +1,124 @@ +import 'package:flutter/material.dart'; + +extension TextStyles on String { + Text get heading1 => getTextWithStyle(this, AppTextStyles.heading1); + + Text get heading2 => getTextWithStyle(this, AppTextStyles.heading2); + + Text get heading3 => getTextWithStyle(this, AppTextStyles.heading3); + + Text get heading4 => getTextWithStyle(this, AppTextStyles.heading4); + + Text get heading5 => getTextWithStyle(this, AppTextStyles.heading5); + + Text get heading6 => getTextWithStyle(this, AppTextStyles.heading6); + + Text get bodyText => getTextWithStyle(this, AppTextStyles.bodyText); + + Text get bodyText2 => getTextWithStyle(this, AppTextStyles.bodyText2); + + Text get tinyFont => getTextWithStyle(this, AppTextStyles.tinyFont); + + Text get overline => getTextWithStyle(this, AppTextStyles.overline); + + Text getTextWithStyle(String string, TextStyle style) => Text(string, style: style); +} + +extension customText on Text { + Text custom({Color color, FontWeight fontWeight, TextAlign align}) { + return Text( + data, + textAlign: align, + style: style.copyWith( + color: color, + fontWeight: fontWeight, + ), + ); + } +} + +abstract class AppTextStyles { + static const TextStyle heading1 = TextStyle( + fontSize: 54, + fontWeight: FontWeight.w500, + height: 0.89, + letterSpacing: -0.81, + fontStyle: FontStyle.normal, + decoration: TextDecoration.none, + ); + + static const TextStyle heading2 = TextStyle( + fontSize: 28, + fontWeight: FontWeight.w700, + height: 1.5, + letterSpacing: -0.56, + fontStyle: FontStyle.normal, + decoration: TextDecoration.none, + ); + + static const TextStyle heading3 = TextStyle( + fontSize: 24, + fontWeight: FontWeight.w700, + height: 1.5, + letterSpacing: -0.12, + fontStyle: FontStyle.normal, + decoration: TextDecoration.none, + ); + + static const TextStyle heading4 = TextStyle( + fontSize: 21, + fontWeight: FontWeight.w500, + height: 1.48, + fontStyle: FontStyle.normal, + decoration: TextDecoration.none, + ); + + static const TextStyle heading5 = TextStyle( + fontSize: 19, + fontWeight: FontWeight.w500, + height: 1.47, + fontStyle: FontStyle.normal, + decoration: TextDecoration.none, + ); + + static const TextStyle heading6 = TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + height: 1.5, + fontStyle: FontStyle.normal, + decoration: TextDecoration.none, + ); + + static const TextStyle bodyText = TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + height: 1.5, + fontStyle: FontStyle.normal, + decoration: TextDecoration.none, + ); + + static const TextStyle bodyText2 = TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500, + height: 1.5, + fontStyle: FontStyle.normal, + decoration: TextDecoration.none, + ); + + static const TextStyle tinyFont = TextStyle( + fontSize: 11, + fontWeight: FontWeight.w500, + height: 1.45, + fontStyle: FontStyle.normal, + decoration: TextDecoration.none, + ); + + static const TextStyle overline = TextStyle( + fontSize: 9, + fontWeight: FontWeight.w500, + height: 1.56, + letterSpacing: 0.05, + fontStyle: FontStyle.normal, + decoration: TextDecoration.none, + ); +} diff --git a/lib/new_views/common_widgets/app_filled_button.dart b/lib/new_views/common_widgets/app_filled_button.dart index 1200908d..b91606fa 100644 --- a/lib/new_views/common_widgets/app_filled_button.dart +++ b/lib/new_views/common_widgets/app_filled_button.dart @@ -1,39 +1,53 @@ import 'package:flutter/material.dart'; import 'package:test_sa/extensions/context_extension.dart'; -import 'package:test_sa/extensions/int_extensions.dart'; -import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/enums/translation_keys.dart'; class AppFilledButton extends StatelessWidget { final VoidCallback onPressed; final TranslationKeys label; final bool maxWidth; + final Color buttonColor; + final Color textColor; + const AppFilledButton({ @required this.onPressed, @required this.label, this.maxWidth = false, + this.buttonColor, + this.textColor, Key key, }) : super(key: key); @override Widget build(BuildContext context) { - return SizedBox( - width: maxWidth ? double.infinity : null, - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 20, - ), - child: ElevatedButton( - style: ElevatedButton.styleFrom( - elevation: 0, - padding: EdgeInsets.symmetric(vertical: 16.toScreenHeight), - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), - ), - onPressed: onPressed, - child: context.translate(label).toHeading6(context, color: Theme.of(context).floatingActionButtonTheme.foregroundColor), - ), - ), - ); + // return SizedBox( + // width: maxWidth ? double.infinity : null, + // child: Padding( + // padding: const EdgeInsets.symmetric( + // horizontal: 16, + // vertical: 20, + // ), + // child: ElevatedButton( + // style: ElevatedButton.styleFrom( + // padding: const EdgeInsets.symmetric(vertical: 16), + // shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), + // ), + // onPressed: onPressed, + // child: Text(context.translate(label)), + // ), + // ), + // ); + return Container( + height: 56, + width: maxWidth ? double.infinity : null, + alignment: Alignment.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: buttonColor ?? Theme.of(context).primaryColor, + ), + child: context.translate(label).heading6.custom(color: textColor)) + .onPress(onPressed); } } diff --git a/lib/new_views/pages/login_page.dart b/lib/new_views/pages/login_page.dart index 897dd320..a449a5e6 100644 --- a/lib/new_views/pages/login_page.dart +++ b/lib/new_views/pages/login_page.dart @@ -4,6 +4,7 @@ import 'package:provider/provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart' show FilesExtension, TextStyleExtension; +import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/enums/translation_keys.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; @@ -18,6 +19,7 @@ import '../common_widgets/app_text_form_field.dart'; class LoginPage extends StatefulWidget { static const String routeName = "/login_page"; + const LoginPage({Key key}) : super(key: key); @override @@ -38,15 +40,9 @@ class _LoginPageState extends State { return Form( key: _formKey, child: Scaffold( - body: Padding( - padding: EdgeInsets.only( - right: 16.toScreenWidth, - left: 16.toScreenWidth, - bottom: 150.toScreenHeight, - top: MediaQuery.of(context).viewPadding.top, - ), - child: Center( - child: SingleChildScrollView( + body: Column( + children: [ + SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, @@ -91,11 +87,12 @@ class _LoginPageState extends State { ), ], ), - ), - ), - ), - floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, - floatingActionButton: AppFilledButton(label: TranslationKeys.login, maxWidth: true, onPressed: _login), + ).center.expanded, + AppFilledButton(label: TranslationKeys.login, maxWidth: true, onPressed: _login, textColor: Colors.white), + ], + ).paddingOnly(left: 16, right: 16, bottom: 24, top: 24), + // floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, + // floatingActionButton: AppFilledButton(label: TranslationKeys.login, maxWidth: true, onPressed: _login), ), ); } diff --git a/lib/views/widgets/input_widget.dart b/lib/views/widgets/input_widget.dart new file mode 100644 index 00000000..fe02aceb --- /dev/null +++ b/lib/views/widgets/input_widget.dart @@ -0,0 +1,140 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; + +class InputWidget extends StatefulWidget { + final String labelText; + final String hintText; + final TextEditingController controller; + final VoidCallback suffixTap; + final bool isEnable; + final bool hasSelection; + final int lines; + final bool isInputTypeNum; + final bool isTextIsPassword; + final bool isBackgroundEnable; + final bool isEnableBorder; + final double verticalPadding; + final double horizontalPadding; + final Function(String) onChange; + final Function(String) validator; + + InputWidget( + this.labelText, + this.hintText, + this.controller, { + Key key, + this.isTextIsPassword = false, + this.suffixTap, + this.validator, + this.isEnable = true, + this.hasSelection = false, + this.isEnableBorder = false, + this.lines = 1, + this.onChange, + this.isInputTypeNum = false, + this.isBackgroundEnable = false, + this.verticalPadding = 10, + this.horizontalPadding = 16, + }) : super(key: key); + + @override + _InputWidgetState createState() { + return _InputWidgetState(); + } +} + +class _InputWidgetState extends State { + bool isObscureText; + + @override + void initState() { + super.initState(); + isObscureText = widget.isTextIsPassword; + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Container( + height: 56, + padding: EdgeInsets.only(left: widget.horizontalPadding, right: widget.horizontalPadding, bottom: widget.verticalPadding, top: widget.verticalPadding), + alignment: Alignment.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: widget.isBackgroundEnable ? Color(0xffF7F7F7) : Colors.white, + border: Border.all( + color: widget.isEnableBorder ? Color(0xffefefef) : Colors.transparent, + width: 1, + ), + boxShadow: const [ + BoxShadow( + color: Color.fromRGBO(0, 0, 0, 0.05), + blurRadius: 10.0, + spreadRadius: 0.0, + offset: Offset(0, 0), + ), + ], + ), + child: InkWell( + onTap: widget.hasSelection ? () {} : null, + child: Row( + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.labelText, + style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + TextFormField( + enabled: widget.isEnable, + scrollPadding: EdgeInsets.zero, + keyboardType: widget.isInputTypeNum ? TextInputType.number : TextInputType.text, + controller: widget.controller, + maxLines: widget.lines, + validator: widget.validator, + obscuringCharacter: "*", + obscureText: isObscureText, + onChanged: widget.onChange, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.primary50 : AppColor.neutral50), + decoration: InputDecoration( + isDense: true, + hintText: widget.hintText, + // hintStyle: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.primary50 : AppColor.neutral50), + hintStyle: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20.withOpacity(.4)), + //suffixIconConstraints: const BoxConstraints(minWidth: 50), + // suffixIcon: widget.suffixTap == null ? null : IconButton(icon: const Icon(Icons.mic, color: MyColors.darkTextColor), onPressed: widget.suffixTap), + contentPadding: EdgeInsets.zero, + border: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + ), + ), + ], + ), + ), + if (widget.isTextIsPassword) ...[ + 16.width, + Icon(isObscureText ? Icons.visibility_rounded : Icons.visibility_off_rounded).onPress(() { + setState(() { + isObscureText = !isObscureText; + }); + }) + ], + if (widget.hasSelection) Icon(Icons.keyboard_arrow_down_outlined), + ], + ), + ), + ); + } +}