From e49399de45000d5f1c4cd5db20767c5a99bdd789 Mon Sep 17 00:00:00 2001 From: zaid_daoud Date: Sun, 15 Oct 2023 15:03:37 +0300 Subject: [PATCH] Improvements on login_page.dart --- assets/translations/ar.json | 2 +- assets/translations/en.json | 2 +- lib/extensions/string_extensions.dart | 86 +++++++++++++++++++ lib/new_views/app_style/app_text_style.dart | 86 +++++++++++++++++++ lib/new_views/app_style/app_themes.dart | 5 +- .../common_widgets/app_filled_button.dart | 4 +- .../common_widgets/app_text_form_field.dart | 84 +++++++++--------- lib/new_views/pages/login_page.dart | 22 ++--- 8 files changed, 230 insertions(+), 61 deletions(-) create mode 100644 lib/new_views/app_style/app_text_style.dart diff --git a/assets/translations/ar.json b/assets/translations/ar.json index e5cb7f49..6a205c3a 100644 --- a/assets/translations/ar.json +++ b/assets/translations/ar.json @@ -5,7 +5,7 @@ "password": "كلمة السر", "username" : "اسم المستخدم", "requiredField" : "الحقل مطلوب", - "passwordLengthMessage" : "كلمة السر أقل من 6 خانات", + "passwordLengthMessage" : "يجب أن تتكون كلمة السر من 6 خانات على الأقل", "overview" : "نظرة عامة", "myRequests" : "طلباتي", "myAssets" : "ممتلكاتي", diff --git a/assets/translations/en.json b/assets/translations/en.json index db99e7b7..58ade3a5 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -5,7 +5,7 @@ "password" : "Password", "username" : "Username", "requiredField" : "Required Field", - "passwordLengthMessage" : "Password length is less than 6 characters", + "passwordLengthMessage" : "Password must has at least 6 characters", "overview" : "Overview", "myRequests" : "My Request", "myAssets" : "My Assets", diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index f49cc81e..2e2a8b21 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -1,3 +1,89 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/app_style/app_text_style.dart'; + +extension CapExtension on String { + String get toCamelCase => "${this[0].toUpperCase()}${substring(1)}"; + + String get inCaps => '${this[0].toUpperCase()}${substring(1)}'; + + String get allInCaps => toUpperCase(); + + String get capitalizeFirstOfEach => trim().isNotEmpty ? trim().toLowerCase().split(" ").map((str) => str.inCaps).join(" ") : ""; +} + +extension TextStyleExtension on String { + Widget toHeading1(BuildContext context, {Color color, int maxLines, FontWeight fontWeight}) => Text( + this, + maxLines: (maxLines != null && maxLines > 0) ? maxLines : null, + style: AppTextStyle.heading1.copyWith(color: color ?? (context.isDark ? AppColor.backgroundLight : AppColor.neutral70), fontWeight: fontWeight), + ); + Widget toHeading2(BuildContext context, {Color color, int maxLines, FontWeight fontWeight}) => Text( + this, + maxLines: (maxLines != null && maxLines > 0) ? maxLines : null, + style: AppTextStyle.heading2.copyWith(color: color ?? (context.isDark ? AppColor.neutral30 : AppColor.neutral50), fontWeight: fontWeight), + ); + Widget toHeading3(BuildContext context, {Color color, int maxLines, FontWeight fontWeight}) => Text( + this, + maxLines: (maxLines != null && maxLines > 0) ? maxLines : null, + style: AppTextStyle.heading3.copyWith(color: color ?? (context.isDark ? AppColor.neutral30 : AppColor.neutral50), fontWeight: fontWeight), + ); + Widget toHeading4(BuildContext context, {Color color, int maxLines, FontWeight fontWeight}) => Text( + this, + maxLines: (maxLines != null && maxLines > 0) ? maxLines : null, + style: AppTextStyle.heading4.copyWith(color: color ?? (context.isDark ? AppColor.neutral30 : AppColor.neutral50), fontWeight: fontWeight), + ); + Widget toHeading5(BuildContext context, {Color color, int maxLines, FontWeight fontWeight}) => Text( + this, + maxLines: (maxLines != null && maxLines > 0) ? maxLines : null, + style: AppTextStyle.heading5.copyWith(color: color ?? (context.isDark ? AppColor.neutral30 : AppColor.neutral50), fontWeight: fontWeight), + ); + Widget toHeading6(BuildContext context, {Color color, int maxLines, FontWeight fontWeight}) => Text( + this, + maxLines: (maxLines != null && maxLines > 0) ? maxLines : null, + style: AppTextStyle.heading6.copyWith(color: color ?? (context.isDark ? AppColor.neutral30 : AppColor.neutral50), fontWeight: fontWeight), + ); + Widget toBody1(BuildContext context, {Color color, int maxLines, FontWeight fontWeight}) => Text( + this, + maxLines: (maxLines != null && maxLines > 0) ? maxLines : null, + style: AppTextStyle.body1.copyWith(color: color ?? (context.isDark ? AppColor.neutral10 : AppColor.neutral20), fontWeight: fontWeight), + ); + Widget toBody2(BuildContext context, {Color color, int maxLines, FontWeight fontWeight}) => Text( + this, + maxLines: (maxLines != null && maxLines > 0) ? maxLines : null, + style: AppTextStyle.body2.copyWith(color: color ?? (context.isDark ? AppColor.neutral10 : AppColor.neutral20), fontWeight: fontWeight), + ); + Widget toTiny(BuildContext context, {Color color, int maxLines, FontWeight fontWeight}) => Text( + this, + maxLines: (maxLines != null && maxLines > 0) ? maxLines : null, + style: AppTextStyle.tiny.copyWith(color: color ?? (context.isDark ? AppColor.neutral10 : AppColor.neutral20), fontWeight: fontWeight), + ); + Widget toOverline(BuildContext context, {Color color, int maxLines, FontWeight fontWeight}) => Text( + this, + maxLines: (maxLines != null && maxLines > 0) ? maxLines : null, + style: AppTextStyle.overline.copyWith(color: color ?? (context.isDark ? AppColor.neutral10 : AppColor.neutral20), fontWeight: fontWeight), + ); +} + +extension FilesExtension on String { + SvgPicture toSvgAsset({ + double width, + double height, + Color color, + BoxFit fit = BoxFit.contain, + }) => + SvgPicture.asset("assets/images/$this.svg", width: width, height: height, color: color, fit: fit); + Image toPngAsset({ + double width, + double height, + Color color, + BoxFit fit = BoxFit.contain, + }) => + Image.asset("assets/images/$this.png", width: width, height: height, color: color, fit: fit); +} + // // import 'package:flutter/cupertino.dart'; // import 'package:intl/intl.dart'; diff --git a/lib/new_views/app_style/app_text_style.dart b/lib/new_views/app_style/app_text_style.dart new file mode 100644 index 00000000..436ec40d --- /dev/null +++ b/lib/new_views/app_style/app_text_style.dart @@ -0,0 +1,86 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; + +class AppTextStyle { + static const fontFamily = "Poppins"; + AppTextStyle._(); + static final TextStyle heading1 = TextStyle( + height: 1.5, + fontSize: 32.toScreenWidth, + letterSpacing: -0.5, + fontFamily: fontFamily, + fontWeight: FontWeight.w700, + decoration: TextDecoration.none, + ); + static final TextStyle heading2 = TextStyle( + height: 1.5, + fontSize: 28.toScreenWidth, + letterSpacing: -0.5, + fontFamily: fontFamily, + fontWeight: FontWeight.w700, + decoration: TextDecoration.none, + ); + static final TextStyle heading3 = TextStyle( + height: 1.5, + fontSize: 24.toScreenWidth, + letterSpacing: -0.5, + fontFamily: fontFamily, + fontWeight: FontWeight.w600, + decoration: TextDecoration.none, + ); + static final TextStyle heading4 = TextStyle( + height: 1.5, + fontSize: 21.toScreenWidth, + fontFamily: fontFamily, + fontWeight: FontWeight.w500, + decoration: TextDecoration.none, + ); + static final TextStyle heading5 = TextStyle( + height: 1.5, + fontSize: 19.toScreenWidth, + letterSpacing: 0, + fontFamily: fontFamily, + fontWeight: FontWeight.w500, + decoration: TextDecoration.none, + ); + static final TextStyle heading6 = TextStyle( + height: 1.5, + fontSize: 16.toScreenWidth, + letterSpacing: 0, + fontFamily: fontFamily, + fontWeight: FontWeight.w500, + decoration: TextDecoration.none, + ); + static final TextStyle body1 = TextStyle( + height: 1.5, + fontSize: 14.toScreenWidth, + letterSpacing: 0, + fontFamily: fontFamily, + fontWeight: FontWeight.w400, + decoration: TextDecoration.none, + ); + static final TextStyle body2 = TextStyle( + height: 1.5, + fontSize: 12.toScreenWidth, + letterSpacing: 0, + fontFamily: fontFamily, + fontWeight: FontWeight.w400, + decoration: TextDecoration.none, + ); + static final TextStyle tiny = TextStyle( + height: 1.5, + fontSize: 11.toScreenWidth, + letterSpacing: 0, + fontFamily: fontFamily, + fontWeight: FontWeight.w500, + decoration: TextDecoration.none, + ); + static final TextStyle overline = TextStyle( + height: 1.5, + fontSize: 9.toScreenWidth, + letterSpacing: 0.5, + fontFamily: fontFamily, + fontWeight: FontWeight.w500, + decoration: TextDecoration.none, + ); +} diff --git a/lib/new_views/app_style/app_themes.dart b/lib/new_views/app_style/app_themes.dart index 8209faf2..cf39314f 100644 --- a/lib/new_views/app_style/app_themes.dart +++ b/lib/new_views/app_style/app_themes.dart @@ -1,10 +1,11 @@ import 'package:flutter/material.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/app_style/app_text_style.dart'; class AppThemes { AppThemes._(); static ThemeData lightTheme = ThemeData.light().copyWith( - textTheme: ThemeData.light().textTheme.apply(fontFamily: "Poppins"), + textTheme: ThemeData.light().textTheme.apply(fontFamily: AppTextStyle.fontFamily), primaryColor: AppColor.primary50, indicatorColor: AppColor.primary50, scaffoldBackgroundColor: AppColor.backgroundLight, @@ -32,7 +33,7 @@ class AppThemes { ); static ThemeData darkTheme = ThemeData.dark().copyWith( - textTheme: ThemeData.dark().textTheme.apply(fontFamily: "Poppins"), + textTheme: ThemeData.dark().textTheme.apply(fontFamily: AppTextStyle.fontFamily), primaryColor: AppColor.primary50, indicatorColor: AppColor.primary50, scaffoldBackgroundColor: AppColor.backgroundDark, diff --git a/lib/new_views/common_widgets/app_filled_button.dart b/lib/new_views/common_widgets/app_filled_button.dart index 9e22968c..905f6c51 100644 --- a/lib/new_views/common_widgets/app_filled_button.dart +++ b/lib/new_views/common_widgets/app_filled_button.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/models/enums/translation_keys.dart'; class AppFilledButton extends StatelessWidget { @@ -24,11 +25,12 @@ class AppFilledButton extends StatelessWidget { ), child: ElevatedButton( style: ElevatedButton.styleFrom( + elevation: 0, padding: const EdgeInsets.symmetric(vertical: 16), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), ), onPressed: onPressed, - child: Text(context.translate(label)), + child: context.translate(label).toHeading6(context, color: Theme.of(context).floatingActionButtonTheme.foregroundColor), ), ), ); diff --git a/lib/new_views/common_widgets/app_text_form_field.dart b/lib/new_views/common_widgets/app_text_form_field.dart index 48f98765..5c3aa0c5 100644 --- a/lib/new_views/common_widgets/app_text_form_field.dart +++ b/lib/new_views/common_widgets/app_text_form_field.dart @@ -3,7 +3,7 @@ import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_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/views/app_style/sizing.dart'; +import 'package:test_sa/new_views/app_style/app_text_style.dart'; class AppTextFormField extends StatefulWidget { final Function(String) onSaved; @@ -21,7 +21,7 @@ class AppTextFormField extends StatefulWidget { final FocusNode node; final Widget suffixIcon; final IconData prefixIconData; - final double prefixIconSize; + final int prefixIconSize; final TextEditingController controller; final TextInputAction textInputAction; final VoidCallback onAction; @@ -63,43 +63,49 @@ class _AppTextFormFieldState extends State { @override Widget build(BuildContext context) { final border = UnderlineInputBorder(borderSide: BorderSide.none, borderRadius: BorderRadius.circular(10)); - return TextFormField( - focusNode: widget.node, - enabled: widget.enable, - onSaved: widget.onSaved, - initialValue: widget.controller != null ? null : widget.initialValue, - validator: widget.validator, - onChanged: widget.onChange, - obscureText: widget.obscureText ?? false, - keyboardType: widget.textInputType, - maxLines: widget.textInputType == TextInputType.multiline ? null : 1, - obscuringCharacter: "*", - controller: widget.controller, - textInputAction: widget.textInputType == TextInputType.multiline ? null : widget.textInputAction ?? TextInputAction.next, - onEditingComplete: widget.onAction ?? () => FocusScope.of(context).nextFocus(), - style: Theme.of(context).textTheme.bodyLarge, - decoration: InputDecoration( - border: border, - disabledBorder: border, - focusedBorder: border, - enabledBorder: border, - errorBorder: border, - contentPadding: EdgeInsets.symmetric(vertical: 8.toScreenHeight, horizontal: 16.toScreenWidth), - constraints: const BoxConstraints(), - suffixIconConstraints: const BoxConstraints(minWidth: 0), - filled: true, - fillColor: context.isDark ? AppColor.neutral50 : Colors.white, - errorStyle: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? AppColor.red50 : AppColor.red60), - floatingLabelStyle: Theme.of(context).textTheme.labelLarge?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500), - hintText: widget.hintText != null ? context.translate(widget.hintText) : null, - labelText: widget.labelText != null ? context.translate(widget.labelText) : null, - suffixIcon: widget.prefixIconData == null - ? null - : Icon( - widget.prefixIconData, - size: widget.prefixIconSize == null ? 20 * AppStyle.getScaleFactor(context) : (widget.prefixIconSize - 10) * AppStyle.getScaleFactor(context), - color: AppColor.neutral70, - ), + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)], + ), + child: TextFormField( + focusNode: widget.node, + enabled: widget.enable, + onSaved: widget.onSaved, + initialValue: widget.controller != null ? null : widget.initialValue, + validator: widget.validator, + onChanged: widget.onChange, + obscureText: widget.obscureText ?? false, + keyboardType: widget.textInputType, + maxLines: widget.textInputType == TextInputType.multiline ? null : 1, + obscuringCharacter: "*", + controller: widget.controller, + textInputAction: widget.textInputType == TextInputType.multiline ? null : widget.textInputAction ?? TextInputAction.next, + onEditingComplete: widget.onAction ?? () => FocusScope.of(context).nextFocus(), + style: AppTextStyle.body1?.copyWith(fontWeight: FontWeight.w500), + decoration: InputDecoration( + border: border, + disabledBorder: border, + focusedBorder: border, + enabledBorder: border, + errorBorder: border, + contentPadding: EdgeInsets.symmetric(vertical: 8.toScreenHeight, horizontal: 16.toScreenWidth), + constraints: const BoxConstraints(), + suffixIconConstraints: const BoxConstraints(minWidth: 0), + filled: true, + fillColor: context.isDark ? AppColor.neutral50 : Colors.white, + errorStyle: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.red50 : AppColor.red60), + floatingLabelStyle: AppTextStyle.body1?.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? null : AppColor.neutral20), + hintText: widget.hintText != null ? context.translate(widget.hintText) : null, + labelText: widget.labelText != null ? context.translate(widget.labelText) : null, + suffixIcon: widget.prefixIconData == null + ? null + : Icon( + widget.prefixIconData, + size: widget.prefixIconSize == null ? 20.toScreenWidth : (widget.prefixIconSize - 10).toScreenWidth, + color: AppColor.neutral70, + ), + ), ), ); } diff --git a/lib/new_views/pages/login_page.dart b/lib/new_views/pages/login_page.dart index b2786a27..897dd320 100644 --- a/lib/new_views/pages/login_page.dart +++ b/lib/new_views/pages/login_page.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:fluttertoast/fluttertoast.dart'; 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/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'; @@ -51,19 +51,10 @@ class _LoginPageState extends State { mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Hero( - tag: "logo", - child: SvgPicture.asset("assets/images/logo.svg", height: 64.toScreenHeight), - ), + Hero(tag: "logo", child: "logo".toSvgAsset(height: 64.toScreenHeight)), 64.height, - Text( - context.translate(TranslationKeys.login), - style: Theme.of(context).textTheme.headlineSmall?.copyWith(color: context.isDark ? AppColor.primary50 : AppColor.neutral50, fontWeight: FontWeight.w600), - ), - Text( - context.translate(TranslationKeys.enterCredsToLogin), - style: Theme.of(context).textTheme.titleMedium?.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20, fontWeight: FontWeight.w500), - ), + context.translate(TranslationKeys.login).toHeading2(context, fontWeight: FontWeight.w600, color: context.isDark ? AppColor.primary50 : AppColor.neutral50), + context.translate(TranslationKeys.enterCredsToLogin).toHeading6(context, color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), 32.height, AppTextFormField( initialValue: _user?.userName, @@ -95,10 +86,7 @@ class _LoginPageState extends State { onTap: () { /// TODO [zaid] : push to another screen }, - child: Text( - context.translate(TranslationKeys.forgotPassword), - style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: AppColor.primary50, fontWeight: FontWeight.w500), - ), + child: context.translate(TranslationKeys.forgotPassword).toBody1(context, color: AppColor.primary50, fontWeight: FontWeight.w500), ), ), ],