app bar & chip

pull/1/head
aamir-csol 2 months ago
parent 255d189ce1
commit 4d76b34608

@ -37,3 +37,5 @@ enum SelectionType { dropdown, calendar }
enum GenderType { male, female } enum GenderType { male, female }
enum MaritalStatusType { single, married, divorced, widowed } enum MaritalStatusType { single, married, divorced, widowed }
enum ChipType { success, error, alert, info, warning }

@ -1,3 +1,4 @@
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
@ -189,3 +190,37 @@ Widget widthSpacer3per() => SizedBox(height: 3.w);
Widget widthSpacer4per() => SizedBox(height: 4.w); Widget widthSpacer4per() => SizedBox(height: 4.w);
Widget widthSpacer5per() => SizedBox(height: 5.w); Widget widthSpacer5per() => SizedBox(height: 5.w);
extension ChipTypeExtension on ChipType {
Color get color {
switch (this) {
case ChipType.success:
return AppColors.successColor; // Replace with your actual color
case ChipType.error:
return AppColors.errorColor; // Replace with your actual color
case ChipType.alert:
return AppColors.alertColor; // Replace with your actual color
case ChipType.info:
return AppColors.infoColor; // Replace with your actual color
case ChipType.warning:
return AppColors.warningColor; // Replace with your actual color
}
}
Color get backgroundColor {
switch (this) {
case ChipType.success:
return AppColors.successLightColor; // Replace with your actual color
case ChipType.error:
return AppColors.errorLightColor; // Replace with your actual color
case ChipType.alert:
return AppColors.alertLightColor; // Replace with your actual color
case ChipType.info:
return AppColors.infoLightColor; // Replace with your actual color
case ChipType.warning:
return AppColors.warningLightColor; // Replace with your actual color
}
}
}

@ -12,6 +12,7 @@ import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/input_widget.dart'; import 'package:hmg_patient_app_new/widgets/input_widget.dart';
import 'package:hmg_patient_app_new/widgets/language_switcher.dart'; import 'package:hmg_patient_app_new/widgets/language_switcher.dart';
import 'package:sizer/sizer.dart'; // Import sizer
class LoginScreen extends StatefulWidget { class LoginScreen extends StatefulWidget {
@override @override
@ -31,10 +32,12 @@ class _LoginScreen extends State<LoginScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Sizer(// Wrap with Sizer
builder: (context, orientation, deviceType) {
return Scaffold( return Scaffold(
appBar: CustomAppBar( appBar: CustomAppBar(
onBackPressed: () { onBackPressed: () {
Navigator.of(context).pop(); // Navigator.of(context).pop();
}, },
onLanguageChanged: (String value) { onLanguageChanged: (String value) {
print(value); print(value);
@ -45,45 +48,26 @@ class _LoginScreen extends State<LoginScreen> {
onTap: () { onTap: () {
FocusScope.of(context).unfocus(); // Dismiss the keyboard when tapping outside FocusScope.of(context).unfocus(); // Dismiss the keyboard when tapping outside
}, },
child: ScrollConfiguration(
behavior: ScrollConfiguration.of(context).copyWith(overscroll: false, physics: const ClampingScrollPhysics()),
child: NotificationListener<OverscrollIndicatorNotification>(
onNotification: (notification) {
notification.disallowIndicator();
return true;
},
child: SingleChildScrollView( child: SingleChildScrollView(
physics: ClampingScrollPhysics(), // Remove NeverScrollableScrollPhysics() child: Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(left: 6.w, right: 6.w),
left: 24,
right: 24,
),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Utils.showLottie( Utils.showLottie(context: context, assetPath: AppAnimations.login, width: 45.w, height: 22.h, repeat: true, fit: BoxFit.cover),
context: context, SizedBox(height: 19.h), // Adjusted to sizer unit
assetPath: AppAnimations.login,
width: MediaQuery.of(context).size.width * 0.45,
height: MediaQuery.of(context).size.height * 0.22,
repeat: true,
fit: BoxFit.cover),
Flexible(
fit: FlexFit.loose,
child: Container(height: MediaQuery.of(context).size.height * 0.18),
),
Text( Text(
LocaleKeys.welcomeToDrSulaiman.tr(), LocaleKeys.welcomeToDrSulaiman.tr(),
style: context.dynamicTextStyle( style: context.dynamicTextStyle(
fontSize: 28, fontSize: 22.sp,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: Color(0xff2B353E), color: AppColors.textColor,
letterSpacing: -0.4, letterSpacing: -0.4,
height: 40 / 28, height: 40 / 28,
), ),
), ),
SizedBox(height: 32), SizedBox(height: 4.h), // Adjusted to sizer unit (approx 32px)
TextInputWidget( TextInputWidget(
labelText: "${LocaleKeys.nationalId.tr()} / ${LocaleKeys.fileNo.tr()}", labelText: "${LocaleKeys.nationalId.tr()} / ${LocaleKeys.fileNo.tr()}",
hintText: "xxxxxxxxx", hintText: "xxxxxxxxx",
@ -94,25 +78,27 @@ class _LoginScreen extends State<LoginScreen> {
autoFocus: true, autoFocus: true,
isBorderAllowed: false, isBorderAllowed: false,
isAllowLeadingIcon: true, isAllowLeadingIcon: true,
padding: EdgeInsets.only(top: 8, bottom: 8, left: 8, right: 8), padding: EdgeInsets.symmetric(vertical: 1.h, horizontal: 2.w),
leadingIcon: AppAssets.student_card, leadingIcon: AppAssets.student_card,
errorMessage: "Please enter a valid national ID or file number",
hasError: true,
), ),
SizedBox(height: 16), SizedBox(height: 2.h), // Adjusted to sizer unit (approx 16px)
CustomButton( CustomButton(
text: LocaleKeys.login.tr(), text: LocaleKeys.login.tr(),
icon: AppAssets.login1, icon: AppAssets.login1,
iconColor: Colors.white, iconColor: Colors.white,
onPressed: () {}, onPressed: () {},
), ),
SizedBox(height: 14), SizedBox(height: 1.8.h), // Adjusted to sizer unit (approx 14px)
Center( Center(
child: RichText( child: RichText(
textAlign: TextAlign.center, textAlign: TextAlign.center,
text: TextSpan( text: TextSpan(
style: context.dynamicTextStyle( style: context.dynamicTextStyle(
color: Colors.black, color: Colors.black,
fontSize: 16, fontSize: 14.sp, // Adjusted to sizer unit
height: 26 / 16, height: 26 / 16, // This height is a ratio, may need re-evaluation
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
children: <TextSpan>[ children: <TextSpan>[
@ -121,23 +107,23 @@ class _LoginScreen extends State<LoginScreen> {
TextSpan( TextSpan(
text: LocaleKeys.registernow.tr(), text: LocaleKeys.registernow.tr(),
style: context.dynamicTextStyle( style: context.dynamicTextStyle(
color: AppColors.bgRedColor, color: AppColors.primaryRedColor,
fontSize: 16, fontSize: 14.sp, // Adjusted to sizer unit
height: 26 / 16, height: 26 / 16, // Ratio
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
recognizer: TapGestureRecognizer()..onTap = () {}, recognizer: TapGestureRecognizer()..onTap = () {},
), ),
], ],
), ),
).withVerticalPadding(16), ).withVerticalPadding(2.h), // Adjusted to sizer unit
), ),
], ],
), ),
), ),
), ),
), ),
),
); );
});
} }
} }

@ -74,7 +74,7 @@ class _SplashScreenState extends State<SplashPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: Color(0xffF8F8F8), backgroundColor: AppColors.whiteColor,
body: Stack( body: Stack(
alignment: Alignment.center, alignment: Alignment.center,
children: [ children: [
@ -89,7 +89,7 @@ class _SplashScreenState extends State<SplashPage> {
children: [ children: [
Text( Text(
"Powered by", "Powered by",
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: AppColors.powerdBy, letterSpacing: -0.56, height: 16 / 14), style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: AppColors.textColor, letterSpacing: -0.56, height: 16 / 14),
), ),
SizedBox( SizedBox(
height: 5, height: 5,

@ -7,7 +7,7 @@ static const deepPurple = Color(0xFF7C65E7);
static const logoColor = Color(0xFF7C65E7); static const logoColor = Color(0xFF7C65E7);
static const buttonColor = Color(0xFF6A46F5); static const buttonColor = Color(0xFF6A46F5);
static const splashBgColor = Color(0xFF3C355D); static const splashBgColor = Color(0xFF3C355D);
static const whiteColor = Color(0xFFffffff);
static const blackColor = Color(0xFF000000); static const blackColor = Color(0xFF000000);
static const lightGray = Color(0xFFF4F5F7); static const lightGray = Color(0xFFF4F5F7);
static const lightPurple = Color(0xFFB7A3E6); static const lightPurple = Color(0xFFB7A3E6);
@ -19,12 +19,28 @@ static const buttonGrayColor = Color(0xffF1F1F1);
static const lightPurpleAlpha = Color(0x5AB7A3E6); static const lightPurpleAlpha = Color(0x5AB7A3E6);
// New UI Colors // New UI Colors
static const Color bgRedColor = Color(0xFFED1C2B); static const whiteColor = Color(0xFFffffff);
static const Color bgRedBorderColor = Color(0xFFED1C2B); static const Color primaryRedColor = Color(0xFFED1C2B);
static const Color primaryRedBorderColor = Color(0xFFED1C2B);
static const Color secondaryLightRedColor = Color(0xFFFEE9EA);
static const Color secondaryLightRedBorderColor = Color(0xFFFEE9EA);
static const Color bgRedLightColor = Color(0xFFFEE9EA); static const Color bgRedLightColor = Color(0xFFFEE9EA);
static const Color bgGreenColor = Color(0xFF18C273); static const Color bgGreenColor = Color(0xFF18C273);
static const Color powerdBy = Color(0xFF333C45); static const Color textColor = Color(0xFF2E3039);
} static const Color borderOnlyColor = Color(0xFF2E3039);
//Chips
static const Color successColor = Color(0xff18C273);
static const Color errorColor = Color(0xFFED1C2B);
static const Color alertColor = Color(0xFFD48D05);
static const Color infoColor = Color(0xFF0B85F7);
static const Color warningColor = Color(0xFFFFCC00);
static const Color greyColor = Color(0xFFEFEFF0);
static const Color successLightColor = Color(0xFF18C27326);
static const Color errorLightColor = Color(0xFFED1C2B1A);
static const Color alertLightColor = Color(0xFFD48D0526);
static const Color infoLightColor = Color(0xFF0B85F726);
static const Color warningLightColor = Color(0xFFFFCC0026);
static const Color greyLightColor = Color(0xFFEFEFF026);
}

@ -28,7 +28,10 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
// Arrow Back with click handler // Arrow Back with click handler
GestureDetector( Expanded(
child: Align(
alignment: Alignment.centerLeft,
child: GestureDetector(
onTap: onBackPressed, onTap: onBackPressed,
child: Utils.buildSvgWithAssets( child: Utils.buildSvgWithAssets(
icon: AppAssets.arrow_back, icon: AppAssets.arrow_back,
@ -36,6 +39,8 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
height: 32, height: 32,
), ),
), ),
),
),
// Logo // Logo
Utils.buildSvgWithAssets( Utils.buildSvgWithAssets(
@ -43,7 +48,10 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
), ),
// Language Selector // Language Selector
LanguageSelector( Expanded(
child: Align(
alignment: Alignment.centerRight,
child: LanguageSelector(
currentLanguage: context.locale.languageCode, currentLanguage: context.locale.languageCode,
showOnlyIcon: false, showOnlyIcon: false,
onLanguageChanged: onLanguageChanged, onLanguageChanged: onLanguageChanged,
@ -52,6 +60,8 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
{'code': 'en', 'name': LocaleKeys.english.tr()} {'code': 'en', 'name': LocaleKeys.english.tr()}
], ],
), ),
),
),
], ],
), ),
centerTitle: true, centerTitle: true,

@ -0,0 +1,72 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
class CustomChipWidget extends StatelessWidget {
final ChipType chipType;
final String chipText;
final String? iconAsset;
final VoidCallback? onTap;
final bool isSelected;
final double borderRadius;
final EdgeInsetsGeometry padding;
const CustomChipWidget({
Key? key,
required this.chipType,
required this.chipText,
this.iconAsset,
this.onTap,
this.isSelected = false,
this.borderRadius = 12,
this.padding = const EdgeInsets.all(8),
}) : super(key: key);
@override
Widget build(BuildContext context) {
final hasIcon = iconAsset != null;
final hasOnTap = onTap != null || hasIcon;
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(borderRadius),
color: isSelected ? chipType.color : chipType.backgroundColor,
border: Border.all(
color: chipType.color,
width: isSelected ? 0 : 1,
),
),
child: InkWell(
onTap: hasOnTap ? onTap : null,
borderRadius: BorderRadius.circular(borderRadius),
child: Container(
padding: padding,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(borderRadius),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (iconAsset != null) ...[
Utils.buildSvgWithAssets(icon: iconAsset!),
const SizedBox(width: 6),
],
Text(
chipText.toUpperCase(),
style: context.dynamicTextStyle(
fontWeight: FontWeight.w500,
fontSize: 14,
color: isSelected ? Colors.white : chipType.color,
letterSpacing: 0.1,
isLanguageSwitcher: true,
),
),
],
),
),
),
);
}
}

@ -2,6 +2,9 @@ import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
// TODO: Import AppColors if bgRedColor is defined there
// import 'package:hmg_patient_app_new/core/ui_utils/app_colors.dart';
class TextInputWidget extends StatelessWidget { class TextInputWidget extends StatelessWidget {
final String labelText; final String labelText;
final String hintText; final String hintText;
@ -19,6 +22,8 @@ class TextInputWidget extends StatelessWidget {
final bool isAllowLeadingIcon; final bool isAllowLeadingIcon;
final String? leadingIcon; final String? leadingIcon;
final bool isCountryDropDown; final bool isCountryDropDown;
final bool hasError;
final String? errorMessage;
// final List<Country> countryList; // final List<Country> countryList;
// final Function(Country)? onCountryChange; // final Function(Country)? onCountryChange;
@ -41,19 +46,28 @@ class TextInputWidget extends StatelessWidget {
this.isAllowLeadingIcon = false, this.isAllowLeadingIcon = false,
this.leadingIcon, this.leadingIcon,
this.isCountryDropDown = false, this.isCountryDropDown = false,
this.hasError = false,
this.errorMessage,
// this.countryList = const [], // this.countryList = const [],
// this.onCountryChange, // this.onCountryChange,
}) : super(key: key); }) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( // Assuming AppColors.bgRedColor exists, otherwise using Colors.red
final errorColor = Colors.red; // Replace with AppColors.bgRedColor if available
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: padding, padding: padding,
alignment: Alignment.center, alignment: Alignment.center,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration( decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: Colors.white, color: Colors.white,
borderRadius: isAllowRadius ? 15 : null, borderRadius: isAllowRadius ? 15 : null,
side: isBorderAllowed ? BorderSide(color: const Color(0xffefefef), width: 1) : null, side: isBorderAllowed ? BorderSide(color: hasError ? errorColor : const Color(0xffefefef), width: 1) : null,
), ),
child: Row( child: Row(
textDirection: Directionality.of(context), textDirection: Directionality.of(context),
@ -71,6 +85,19 @@ class TextInputWidget extends StatelessWidget {
), ),
], ],
), ),
),
if (hasError && errorMessage != null)
Padding(
padding: const EdgeInsets.only(top: 4.0, left: 12.0), // Adjust padding as needed
child: Text(
errorMessage!,
style: TextStyle(
color: errorColor,
fontSize: 12,
),
),
),
],
); );
} }

@ -43,19 +43,16 @@ class _LanguageSelectorState extends State<LanguageSelector> {
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
color: Color(0xFFFEE9EA), color: AppColors.secondaryLightRedColor,
), ),
child: InkWell( child: InkWell(
onTap: () { onTap: () {
final newLanguage = widget.currentLanguage == 'ar' ? 'en' : 'ar'; final newLanguage = widget.currentLanguage == 'ar' ? 'en' : 'ar';
print(newLanguage);
widget.onLanguageChanged(newLanguage); widget.onLanguageChanged(newLanguage);
}, },
child: Container( child: Container(
padding: EdgeInsets.all(8), padding: EdgeInsets.all(8),
decoration: BoxDecoration( decoration: BoxDecoration(borderRadius: BorderRadius.circular(12)),
borderRadius: BorderRadius.circular(12),
),
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@ -66,7 +63,7 @@ class _LanguageSelectorState extends State<LanguageSelector> {
style: context.dynamicTextStyle( style: context.dynamicTextStyle(
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
fontSize: 14, fontSize: 14,
color: AppColors.bgRedColor, color: AppColors.primaryRedColor,
letterSpacing: 0.1, letterSpacing: 0.1,
isLanguageSwitcher: true, isLanguageSwitcher: true,
), ),

Loading…
Cancel
Save