Compare commits

..

No commits in common. '87830e17ab98a34d0f2c3c17d82b8bcf0f970479' and '6a09c2ec07c9ff5e09a909d4d586b561baa127d9' have entirely different histories.

@ -1,5 +0,0 @@
<svg width="19" height="19" viewBox="0 0 19 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.46948 5.26367C5.46948 3.08905 7.23236 1.32617 9.40698 1.32617C11.5816 1.32617 13.3445 3.08905 13.3445 5.26367C13.3445 7.43829 11.5816 9.20117 9.40698 9.20117C7.23236 9.20117 5.46948 7.43829 5.46948 5.26367Z" fill="white"/>
<path d="M14.282 10.8887C14.6962 10.8887 15.032 11.2245 15.032 11.6387L15.032 13.5137H16.907C17.3212 13.5137 17.657 13.8495 17.657 14.2637C17.657 14.6779 17.3212 15.0137 16.907 15.0137H15.032V16.8887C15.032 17.3029 14.6962 17.6387 14.282 17.6387C13.8678 17.6387 13.532 17.3029 13.532 16.8887V15.0137L11.657 15.0137C11.2428 15.0137 10.907 14.6779 10.907 14.2637C10.907 13.8495 11.2428 13.5137 11.657 13.5137L13.532 13.5137L13.532 11.6387C13.532 11.2245 13.8678 10.8887 14.282 10.8887Z" fill="white"/>
<path d="M12.4228 11.3881C12.4366 11.2848 12.389 11.1802 12.2947 11.1358C11.5181 10.7701 10.6961 10.5285 9.85994 10.4106C9.06204 10.298 8.25072 10.298 7.45282 10.4106C6.35447 10.5655 5.28042 10.9338 4.30178 11.5166C4.21459 11.5685 4.10681 11.6293 3.98488 11.6981C3.45027 11.9997 2.64205 12.4557 2.08842 12.9975C1.74217 13.3365 1.41318 13.7831 1.35337 14.3302C1.28977 14.9121 1.54361 15.4582 2.05288 15.9434C2.93146 16.7804 3.9858 17.4512 5.34953 17.4512L11.9632 17.4512C12.05 17.4512 12.1356 17.4485 12.2199 17.4431C12.3579 17.4345 12.4458 17.2977 12.4259 17.1609C12.4129 17.072 12.4063 16.9811 12.4063 16.8887V16.3637C12.4063 16.2394 12.3055 16.1387 12.1812 16.1387H11.6563C10.6207 16.1387 9.78125 15.2992 9.78125 14.2637C9.78125 13.2281 10.6207 12.3887 11.6563 12.3887H12.1812C12.3055 12.3887 12.4063 12.2879 12.4063 12.1637V11.6387C12.4063 11.5537 12.4119 11.4701 12.4228 11.3881Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

@ -1,4 +0,0 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="40" height="40" rx="10" fill="#EFEFF0"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.2875 11.1375C11.0186 11.514 10.25 12.681 10.25 13.9011L10.25 23.1109V23.1109C10.25 24.0675 10.25 24.8561 10.3336 25.5045C10.4222 26.1908 10.6103 26.7808 11.023 27.3226C11.7991 28.3414 13.0649 28.6825 14.5937 29.0945C17.3925 29.8507 20.3234 30.2985 22.9379 30.5539C24.2263 30.6799 25.342 30.7889 26.1943 30.7385C27.0973 30.6852 27.864 30.4566 28.5222 29.8551C29.1878 29.2469 29.4818 28.4721 29.619 27.5411C29.7501 26.6519 29.75 25.523 29.75 24.1294V22.005C29.75 20.6461 29.75 19.5558 29.6434 18.6993C29.5334 17.8161 29.2987 17.0681 28.7429 16.4687C28.3097 16.0014 27.751 15.7218 27.1061 15.5394C26.8205 15.4586 26.6777 15.4182 26.6163 15.3223C26.5549 15.2265 26.5772 15.0844 26.6217 14.8C26.6965 14.3217 26.7469 13.8046 26.7499 13.287C26.7554 12.3019 26.5913 11.1247 25.887 10.2663C24.9266 9.09578 23.4925 9.22142 22.6683 9.29363C17.7941 9.70754 14.2397 10.5581 12.2875 11.1375ZM22.7412 11.1692C23.2217 11.1284 23.558 11.1064 23.8415 11.1514C24.0784 11.1889 24.2313 11.2663 24.3657 11.4302C24.6498 11.7764 24.8139 12.4144 24.809 13.2768C24.8064 13.7428 24.7549 14.2195 24.6803 14.6563C24.6397 14.8938 24.6194 15.0125 24.5281 15.084C24.4367 15.1555 24.3108 15.1461 24.0591 15.1274C23.7397 15.1037 23.4049 15.0805 23.0559 15.0563C18.8417 14.7643 15.2273 14.2127 12.8773 13.6991C12.5868 13.6356 12.4415 13.6039 12.404 13.4099C12.3665 13.216 12.4521 13.1578 12.6233 13.0413C12.6967 12.9914 12.776 12.9535 12.8581 12.9291C14.6959 12.3837 18.0184 11.5703 22.7412 11.1692ZM24.5 21C25.6046 21 26.5 21.8954 26.5 23C26.5 24.1046 25.6046 25 24.5 25C23.3954 25 22.5 24.1046 22.5 23C22.5 21.8954 23.3954 21 24.5 21Z" fill="#8F9AA3"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

@ -51,8 +51,6 @@ class AppAssets {
static const String insurance_update_icon = '$svgBasePath/insurance_update.svg';
static const String home_calendar_icon = '$svgBasePath/home_calendar_icon.svg';
static const String add_icon = '$svgBasePath/add_icon.svg';
static const String add_family = '$svgBasePath/add_family.svg';
static const String wallet = '$svgBasePath/wallet.svg';
static const String livecare_icon = '$svgBasePath/livecare_icon.svg';
static const String file_icon = '$svgBasePath/file_icon.svg';
static const String checkmark_icon = '$svgBasePath/checkmark_icon.svg';

@ -34,8 +34,7 @@ extension EmailValidator on String {
),
);
Widget toText10({Color? color, FontWeight? weight, bool isBold = false, bool isUnderLine = false, int? maxlines, FontStyle? fontStyle, TextOverflow? textOverflow, double letterSpacing = -1}) =>
Text(
Widget toText10({Color? color, FontWeight? weight, bool isBold = false, bool isUnderLine = false, int? maxlines, FontStyle? fontStyle, TextOverflow? textOverflow, double letterSpacing = -1}) => Text(
this,
maxLines: maxlines,
overflow: textOverflow,
@ -120,7 +119,16 @@ extension EmailValidator on String {
),
);
Widget toText13({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int maxLine = 0, FontWeight? weight, double? letterSpacing = -1}) => Text(
Widget toText13({
Color? color,
bool isUnderLine = false,
bool isBold = false,
bool isCenter = false,
int maxLine = 0,
FontWeight? weight,
double? letterSpacing = -1
}) =>
Text(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: (maxLine > 0) ? maxLine : null,
@ -185,12 +193,11 @@ extension EmailValidator on String {
style: TextStyle(color: color ?? AppColors.blackColor, fontSize: 17.fSize, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
);
Widget toText18({Color? color, FontWeight? weight, bool isBold = false, bool isCenter = false, int? maxlines, TextOverflow? textOverflow}) => Text(
Widget toText18({Color? color, bool isBold = false, bool isCenter = false, int? maxlines}) => Text(
maxLines: maxlines,
textAlign: isCenter ? TextAlign.center : null,
this,
overflow: textOverflow,
style: TextStyle(fontSize: 18.fSize, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal), color: color ?? AppColors.blackColor, letterSpacing: -0.4),
style: TextStyle(fontSize: 18.fSize, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: color ?? AppColors.blackColor, letterSpacing: -0.4),
);
Widget toText19({Color? color, bool isBold = false}) => Text(
@ -198,7 +205,7 @@ extension EmailValidator on String {
style: TextStyle(fontSize: 19.fSize, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: color ?? AppColors.blackColor, letterSpacing: -0.4),
);
Widget toText20({Color? color, FontWeight? weight, bool isBold = false}) => Text(
Widget toText20({Color? color,FontWeight? weight, bool isBold = false}) => Text(
this,
style: TextStyle(fontSize: 20.fSize, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal), color: color ?? AppColors.blackColor, letterSpacing: -0.4),
);

@ -6,7 +6,6 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart';
@ -51,12 +50,12 @@ class OTPWidget extends StatefulWidget {
final TextInputType keyboardType;
final EdgeInsets pinBoxOuterPadding;
const OTPWidget({
OTPWidget({
Key? key,
this.maxLength = 4,
this.controller,
this.pinBoxWidth = 70.0,
this.pinBoxHeight = 70.0,
this.pinBoxHeight = 100.0,
this.pinTextStyle,
this.onDone,
this.defaultBorderColor = Colors.black,
@ -128,9 +127,7 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi
_highlightAnimationController = AnimationController(vsync: this);
_initTextController();
_calculateStrList();
if (widget.controller != null) {
widget.controller!.addListener(_controllerListener);
}
widget.controller!.addListener(_controllerListener);
focusNode.addListener(_focusListener);
}
@ -193,9 +190,7 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi
focusNode.removeListener(_focusListener);
}
_highlightAnimationController.dispose();
if (widget.controller != null) {
widget.controller!.removeListener(_controllerListener);
}
widget.controller?.removeListener(_controllerListener);
super.dispose();
}
@ -236,7 +231,7 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi
width: 0.0,
),
);
return Container(
return SizedBox(
width: _width,
height: widget.pinBoxHeight,
child: TextField(
@ -246,6 +241,8 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi
controller: widget.controller,
keyboardType: widget.keyboardType,
inputFormatters: widget.keyboardType == TextInputType.number ? <TextInputFormatter>[FilteringTextInputFormatter.digitsOnly] : null,
// Enable SMS autofill
autofillHints: const [AutofillHints.oneTimeCode],
style: TextStyle(
height: 0.1,
color: Colors.transparent,
@ -304,28 +301,33 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi
return _buildPinCode(i, context);
});
return Row(
children: pinCodes,
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: pinCodes,
);
}
Widget _buildPinCode(int i, BuildContext context) {
Color pinBoxColor = widget.pinBoxColor;
Color borderColor;
Color pinBoxColor;
// Determine if OTP is complete
bool isComplete = text.length == widget.maxLength;
if (widget.hasError) {
pinBoxColor = widget.errorBorderColor;
borderColor = widget.errorBorderColor;
pinBoxColor = widget.pinBoxColor;
} else if (isComplete) {
borderColor = Colors.transparent;
pinBoxColor = AppColors.successColor;
} else if (i < text.length) {
pinBoxColor = AppColors.blackBgColor; // Custom color for filled boxes
borderColor = Colors.transparent;
pinBoxColor = AppColors.blackBgColor;
} else {
borderColor = Colors.transparent;
pinBoxColor = widget.pinBoxColor;
}
// Change color to success when all fields are complete
if (text.length == widget.maxLength) {
pinBoxColor = AppColors.successColor;
}
EdgeInsets insets;
if (i == 0) {
insets = EdgeInsets.only(
@ -344,21 +346,22 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi
} else {
insets = widget.pinBoxOuterPadding;
}
return AnimatedContainer(
duration: const Duration(milliseconds: 200),
curve: Curves.easeInOut,
return Container(
key: ValueKey<String>("container$i"),
alignment: Alignment.center,
padding: EdgeInsets.symmetric(vertical: 4.0, horizontal: 1.0),
margin: insets,
child: _animatedTextBox(strList[i], i),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
decoration: BoxDecoration(
border: Border.all(
color: borderColor,
width: widget.pinBoxBorderWidth,
),
color: pinBoxColor,
borderRadius: widget.pinBoxRadius,
borderRadius: BorderRadius.circular(widget.pinBoxRadius),
),
width: widget.pinBoxWidth,
height: widget.pinBoxHeight,
child: _animatedTextBox(strList[i], i),
);
}
@ -404,12 +407,10 @@ class OTPVerificationScreen extends StatefulWidget {
class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
final int _otpLength = 4;
late final TextEditingController _otpController;
late TextEditingController _otpController;
Timer? _resendTimer;
int _resendTime = 60;
bool _isOtpComplete = false;
bool _isVerifying = false; // Flag to prevent multiple verification calls
@override
void initState() {
@ -436,25 +437,27 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
}
void _onOtpChanged(String value) {
setState(() {
_isOtpComplete = value.length == _otpLength;
});
if (_isOtpComplete && !_isVerifying) {
_isVerifying = true;
_verifyOtp(value);
} else if (!_isOtpComplete) {
// Reset the flag when OTP is incomplete (user is editing)
_isVerifying = false;
// Handle clipboard paste or programmatic input
if (value.length > 1) {
String? otp = _extractOtpFromText(value);
if (otp != null) {
autoFillOtp(otp);
return;
}
}
// The OTPWidget will automatically call onDone when complete
// This method can be used for any additional logic on text change
}
void _onOtpCompleted(String otp) {
debugPrint('OTP Completed: $otp');
widget.checkActivationCode(int.parse(otp));
}
void _resendOtp() {
if (_resendTime == 0) {
setState(() {
_resendTime = 60;
_isVerifying = false; // Reset verification flag
});
setState(() => _resendTime = 60);
_startResendTimer();
autoFillOtp("1234");
widget.onResendOTPPressed(widget.phoneNumber);
@ -466,6 +469,68 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
return phone.length > 4 ? '05xxxxxx${phone.substring(phone.length - 2)}' : phone;
}
/// Extract OTP from text using multiple patterns
String? _extractOtpFromText(String text) {
// Pattern 1: Find 4-6 consecutive digits
RegExp digitPattern = RegExp(r'\b\d{4,6}\b');
Match? match = digitPattern.firstMatch(text);
if (match != null) {
String digits = match.group(0)!;
if (digits.length >= _otpLength) {
return digits.substring(0, _otpLength);
}
}
// Pattern 2: Find digits separated by spaces or special characters
String cleanedText = text.replaceAll(RegExp(r'[^\d]'), '');
if (cleanedText.length >= _otpLength) {
return cleanedText.substring(0, _otpLength);
}
return null;
}
/// Paste OTP from clipboard
Future<void> _pasteFromClipboard() async {
try {
ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain);
if (data != null && data.text != null) {
String clipboardText = data.text!;
String? otp = _extractOtpFromText(clipboardText);
if (otp != null) {
autoFillOtp(otp);
// Show feedback to user
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('OTP pasted: $otp'),
duration: const Duration(seconds: 2),
backgroundColor: AppColors.successColor,
),
);
} else {
// Show error if no valid OTP found
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('No valid OTP found in clipboard'),
duration: Duration(seconds: 2),
),
);
}
}
} catch (e) {
debugPrint('Error pasting from clipboard: $e');
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Failed to paste from clipboard'),
duration: Duration(seconds: 2),
),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
@ -495,30 +560,35 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
),
SizedBox(height: 40.h),
// OTP Input Fields using new OTP Widget
// OTP Input Fields using new OTPWidget
Center(
child: OTPWidget(
maxLength: _otpLength,
controller: _otpController,
pinBoxWidth: 70.h,
pinBoxHeight: 100,
pinBoxRadius: 16,
pinBoxBorderWidth: 0,
pinBoxOuterPadding: EdgeInsets.symmetric(horizontal: 4.h),
defaultBorderColor: Colors.transparent,
textBorderColor: Colors.transparent,
pinBoxColor: AppColors.whiteColor,
autoFocus: true,
onTextChanged: _onOtpChanged,
pinTextStyle: TextStyle(
fontSize: 40.fSize,
fontWeight: FontWeight.bold,
color: AppColors.whiteColor,
child: AutofillGroup(
child: OTPWidget(
maxLength: _otpLength,
controller: _otpController,
pinBoxWidth: 75.h,
pinBoxHeight: 100.h,
autoFocus: true,
pinBoxRadius: 16,
pinBoxBorderWidth: 0,
pinBoxOuterPadding: EdgeInsets.symmetric(horizontal: 4.h),
defaultBorderColor: Colors.transparent,
textBorderColor: Colors.transparent,
errorBorderColor: AppColors.primaryRedColor,
pinBoxColor: AppColors.whiteColor,
pinTextStyle: TextStyle(
fontSize: 50.fSize,
fontWeight: FontWeight.bold,
color: AppColors.whiteColor,
),
onTextChanged: _onOtpChanged,
onDone: _onOtpCompleted,
),
),
),
const SizedBox(height: 32),
const SizedBox(height: 16),
// Resend OTP
Row(
@ -550,15 +620,50 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
);
}
void _verifyOtp(String otp) {
debugPrint('Verifying OTP: $otp');
widget.checkActivationCode(int.parse(otp));
}
/// Auto fill OTP into text fields
void autoFillOtp(String otp) {
if (otp.length != _otpLength) return;
_isVerifying = false; // Reset flag before setting new OTP
_otpController.text = otp;
// Clear any existing text first
_otpController.clear();
// Add a small delay to ensure the UI is updated
Future.delayed(const Duration(milliseconds: 50), () {
_otpController.text = otp;
// Move cursor to the end
_otpController.selection = TextSelection.fromPosition(
TextPosition(offset: otp.length),
);
});
}
/// Clear OTP fields
void clearOtp() {
_otpController.clear();
}
/// Get current OTP value
String getCurrentOtp() {
return _otpController.text;
}
/// Check if OTP is complete
bool isOtpComplete() {
return _otpController.text.length == _otpLength;
}
/// Simulate SMS received with OTP (for testing purposes)
void simulateSMSReceived(String otp) {
if (otp.length == _otpLength && RegExp(r'^\d+$').hasMatch(otp)) {
autoFillOtp(otp);
// Show a brief indicator that SMS was detected
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('OTP detected from SMS: $otp'),
duration: const Duration(seconds: 2),
backgroundColor: AppColors.successColor,
),
);
}
}
}

@ -1,8 +0,0 @@
import 'package:flutter/foundation.dart';
class ProfileSettingsViewModel extends ChangeNotifier {
void notify(){
notifyListeners();
}
}

@ -17,7 +17,6 @@ import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_mode
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/payfort/payfort_view_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart';
import 'package:hmg_patient_app_new/features/radiology/radiology_view_model.dart';
import 'package:hmg_patient_app_new/routes/app_routes.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
@ -103,9 +102,6 @@ void main() async {
errorHandlerService: getIt(),
),
),
ChangeNotifierProvider<ProfileSettingsViewModel>(
create: (_) => ProfileSettingsViewModel(),
),
ChangeNotifierProvider<MyAppointmentsViewModel>(
create: (_) => MyAppointmentsViewModel(
myAppointmentsRepo: getIt(),

@ -1,173 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_swiper_view/flutter_swiper_view.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_export.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';
import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart';
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'package:provider/provider.dart';
class ProfileSettings extends StatefulWidget {
ProfileSettings({Key? key}) : super(key: key);
@override
_ProfileSettingsState createState() {
return _ProfileSettingsState();
}
}
class _ProfileSettingsState extends State<ProfileSettings> {
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
int length = 3;
final SwiperController _controller = SwiperController();
int _index = 0;
@override
Widget build(BuildContext context) {
return CollapsingListView(
title: "Profile & Settings".needTranslation,
logout: () {},
isClose: true,
child: SingleChildScrollView(
padding: EdgeInsets.only(top: 24, bottom: 24),
physics: NeverScrollableScrollPhysics(),
child: Consumer<ProfileSettingsViewModel>(
builder: (context, model, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Swiper(
itemCount: length,
layout: SwiperLayout.STACK,
loop: true,
itemWidth: MediaQuery.of(context).size.width - 42,
indicatorLayout: PageIndicatorLayout.COLOR,
axisDirection: AxisDirection.right,
controller: _controller,
itemHeight: 210 + 16,
pagination: const SwiperPagination(
alignment: Alignment.bottomCenter,
margin: EdgeInsets.only(top: 210 + 8 + 24),
builder: DotSwiperPaginationBuilder(color: Color(0xffD9D9D9), activeColor: AppColors.blackBgColor),
),
itemBuilder: (BuildContext context, int index) {
return FamilyCardWidget().paddingOnly(right: 16);
},
),
GridView(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, childAspectRatio: 105 / 105, crossAxisSpacing: 9, mainAxisSpacing: 9),
physics: const NeverScrollableScrollPhysics(),
padding: const EdgeInsets.all(24),
shrinkWrap: true,
children: [
Container(
padding: EdgeInsets.all(16),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: true,
),
child: Column(
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.wallet, width: 40.h, height: 40.h),
],
)
],
),
)
],
)
],
);
},
),
),
);
}
}
class FamilyCardWidget extends StatelessWidget {
FamilyCardWidget();
@override
Widget build(BuildContext context) {
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: true,
),
child: Column(
children: [
Column(
spacing: 8.h,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 8.h,
children: [
Image.asset(true ? AppAssets.male_img : AppAssets.femaleImg, width: 56.h, height: 56.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 0.h,
mainAxisSize: MainAxisSize.min,
children: [
"Mahmoud Shrouf Shrouf".toText18(isBold: true, weight: FontWeight.w600, textOverflow: TextOverflow.ellipsis, maxlines: 1),
AppCustomChipWidget(
icon: AppAssets.file_icon,
labelText: "File no: 3423443",
iconSize: 14,
),
],
).expanded,
Icon(Icons.qr_code, size: 56)
],
).expanded,
SizedBox(
width: double.infinity,
child: Wrap(
alignment: WrapAlignment.start,
spacing: 8.h,
children: [
AppCustomChipWidget(labelText: "35 Years Old"),
AppCustomChipWidget(labelText: "Blood: A+"),
AppCustomChipWidget(
icon: AppAssets.insurance_active_icon,
labelText: "Insurance Active",
iconColor: AppColors.bgGreenColor,
iconSize: 14,
backgroundColor: AppColors.bgGreenColor.withValues(alpha: 0.15),
),
],
),
),
],
).paddingOnly(top: 16, right: 16, left: 16, bottom: 12).expanded,
Divider(
height: 1,
thickness: 1,
color: Color(0x30D2D2D2),
),
CustomButton(icon: AppAssets.add_family, text: "Add a new family member", onPressed: () {}).paddingOnly(top: 12, right: 16, left: 16, bottom: 16),
],
),
);
}
}

@ -78,7 +78,6 @@ dependencies:
keyboard_actions: ^4.2.0
path_provider: ^2.0.8
open_filex: ^4.7.0
flutter_swiper_view: ^1.1.8
dev_dependencies:
flutter_test:

Loading…
Cancel
Save