Merge branch 'refs/heads/master' into faiz_dev
# Conflicts: # lib/core/api/api_client.dart # lib/core/api_consts.dart # lib/presentation/contact_us/feedback_page.dartfaiz_dev
commit
b75e72636a
@ -0,0 +1,26 @@
|
||||
<resources>
|
||||
<color name="payment_sdk_primary_color">#ffffff</color>
|
||||
<color name="payment_sdk_secondary_color">#ED1C2B</color>
|
||||
<color name="payment_sdk_status_bar_color">#444647</color>
|
||||
<color name="payment_sdk_primary_font_color">#2E3039</color>
|
||||
<color name="payment_sdk_secondary_font_color">#2E3039</color>
|
||||
<color name="payment_sdk_hint_font_color">#a5a5a5</color>
|
||||
<color name="payment_sdk_stroke_color">#e1e1e1</color>
|
||||
<color name="payment_sdk_button_text_color">#FFF</color>
|
||||
<color name="payment_sdk_title_text_color">#1e1e1e</color>
|
||||
<color name="payment_sdk_button_background_color">#ED1C2B</color>
|
||||
<color name="payment_sdk_background_color">#F9FAFD</color>
|
||||
<color name="payment_sdk_blue_F2FAFD">#F2FAFD</color>
|
||||
<color name="payment_sdk_error_text_color">#EC2213</color>
|
||||
<color name="payment_sdk_back_black_dim">#4D6E6E6E</color>
|
||||
<color name="payment_sdk_input_field_background_color">#FFFFFFFF</color>
|
||||
<color name="payment_sdk_enabled_switch_track_color">#00000000</color>
|
||||
<color name="payment_sdk_enabled_switch_handle_color">#3db39e</color>
|
||||
<color name="payment_sdk_disabled_switch_track_color">#00000000</color>
|
||||
<color name="payment_sdk_disabled_switch_handle_color">#c7c7c7</color>
|
||||
<color name="payment_sdk_switch_stroke_color">#4c4c4c</color>
|
||||
<color name="payment_sdk_amount_font_color">#4c4c4c</color>
|
||||
<color name="payment_sdk_original_amount_font_color">#a5a5a5</color>
|
||||
<color name="payment_sdk_billing_header_background_color">#ED1C2B</color>
|
||||
<color name="payment_sdk_billing_text_color">#FFF</color>
|
||||
</resources>
|
||||
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="120" height="120" fill="#EFF1F3"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M33.2503 38.4816C33.2603 37.0472 34.4199 35.8864 35.8543 35.875H83.1463C84.5848 35.875 85.7503 37.0431 85.7503 38.4816V80.5184C85.7403 81.9528 84.5807 83.1136 83.1463 83.125H35.8543C34.4158 83.1236 33.2503 81.957 33.2503 80.5184V38.4816ZM80.5006 41.1251H38.5006V77.8751L62.8921 53.4783C63.9172 52.4536 65.5788 52.4536 66.6039 53.4783L80.5006 67.4013V41.1251ZM43.75 51.6249C43.75 54.5244 46.1005 56.8749 49 56.8749C51.8995 56.8749 54.25 54.5244 54.25 51.6249C54.25 48.7254 51.8995 46.3749 49 46.3749C46.1005 46.3749 43.75 48.7254 43.75 51.6249Z" fill="#687787"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 892 B |
@ -0,0 +1,12 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3.9384 3.88371e-06C3.28428 -5.8582e-05 2.69656 -0.000114493 2.22085 0.0638424C1.70149 0.133668 1.16868 0.295802 0.732241 0.732241C0.295802 1.16868 0.133668 1.70149 0.0638424 2.22085C-0.000114493 2.69656 -5.8582e-05 3.28428 3.88371e-06 3.9384L3.88371e-06 4.06161C-5.8582e-05 4.71574 -0.000114493 5.30346 0.0638424 5.77916C0.133668 6.29852 0.295802 6.83134 0.732241 7.26777C1.16868 7.70421 1.70149 7.86635 2.22085 7.93617C2.69656 8.00013 3.28427 8.00007 3.9384 8.00001H4.06162C4.71574 8.00007 5.30346 8.00013 5.77916 7.93617C6.29852 7.86635 6.83134 7.70421 7.26777 7.26777C7.70421 6.83134 7.86635 6.29852 7.93617 5.77916C8.00013 5.30346 8.00007 4.71574 8.00001 4.06162V3.9384C8.00007 3.28427 8.00013 2.69656 7.93617 2.22085C7.86635 1.70149 7.70421 1.16868 7.26777 0.732241C6.83134 0.295802 6.29852 0.133668 5.77916 0.0638424C5.30346 -0.000114493 4.71574 -5.8582e-05 4.06161 3.88371e-06L3.9384 3.88371e-06Z" fill="#8F9AA3"/>
|
||||
<path d="M3.9384 12C3.28428 11.9999 2.69655 11.9999 2.22085 12.0638C1.70149 12.1337 1.16868 12.2958 0.732241 12.7322C0.295802 13.1687 0.133668 13.7015 0.0638424 14.2209C-0.000114493 14.6966 -5.8582e-05 15.2843 3.88371e-06 15.9384L3.88371e-06 16.0616C-5.8582e-05 16.7157 -0.000114493 17.3035 0.0638424 17.7792C0.133668 18.2985 0.295802 18.8313 0.732241 19.2678C1.16868 19.7042 1.70149 19.8663 2.22085 19.9362C2.69656 20.0001 3.28427 20.0001 3.9384 20H4.06162C4.71574 20.0001 5.30346 20.0001 5.77916 19.9362C6.29852 19.8663 6.83134 19.7042 7.26777 19.2678C7.70421 18.8313 7.86635 18.2985 7.93617 17.7792C8.00013 17.3035 8.00007 16.7157 8.00001 16.0616V15.9384C8.00007 15.2843 8.00013 14.6966 7.93617 14.2209C7.86635 13.7015 7.70421 13.1687 7.26777 12.7322C6.83134 12.2958 6.29852 12.1337 5.77916 12.0638C5.30346 11.9999 4.71575 11.9999 4.06163 12H3.9384Z" fill="#8F9AA3"/>
|
||||
<path d="M0 10C0 9.44771 0.447715 9 1 9L7 9C7.55228 9 8 9.44772 8 10C8 10.5523 7.55228 11 7 11L1 11C0.447715 11 0 10.5523 0 10Z" fill="#8F9AA3"/>
|
||||
<path d="M11 1C11 0.447715 10.5523 0 10 0C9.44771 0 9 0.447715 9 1L9 6C9 6.55228 9.44771 7 10 7C10.5523 7 11 6.55228 11 6L11 1Z" fill="#8F9AA3"/>
|
||||
<path d="M15.9384 3.88371e-06L16.0616 3.88371e-06C16.7157 -5.8582e-05 17.3035 -0.000114493 17.7792 0.0638424C18.2985 0.133668 18.8313 0.295802 19.2678 0.732241C19.7042 1.16868 19.8663 1.70149 19.9362 2.22085C20.0001 2.69656 20.0001 3.28427 20 3.9384V4.06162C20.0001 4.71574 20.0001 5.30346 19.9362 5.77916C19.8663 6.29852 19.7042 6.83134 19.2678 7.26777C18.8313 7.70421 18.2985 7.86635 17.7792 7.93617C17.3035 8.00013 16.7157 8.00007 16.0616 8.00001H15.9384C15.2843 8.00007 14.6966 8.00013 14.2209 7.93617C13.7015 7.86635 13.1687 7.70421 12.7322 7.26777C12.2958 6.83134 12.1337 6.29852 12.0638 5.77916C11.9999 5.30346 11.9999 4.71575 12 4.06163V3.9384C11.9999 3.28428 11.9999 2.69655 12.0638 2.22085C12.1337 1.70149 12.2958 1.16868 12.7322 0.732241C13.1687 0.295802 13.7015 0.133668 14.2209 0.0638424C14.6966 -0.000114493 15.2843 -5.8582e-05 15.9384 3.88371e-06Z" fill="#8F9AA3"/>
|
||||
<path d="M12.9384 9C12.2843 8.99994 11.6966 8.99989 11.2209 9.06384C10.7015 9.13367 10.1687 9.2958 9.73224 9.73224C9.2958 10.1687 9.13367 10.7015 9.06384 11.2209C8.99989 11.6966 8.99994 12.2843 9 12.9384L9.00001 13C9.00001 13.5523 9.44772 14 10 14C10.5523 14 11 13.5523 11 13C11 12.2646 11.0021 11.8137 11.046 11.4873C11.0846 11.2005 11.1394 11.1526 11.1459 11.1469L11.1469 11.1459C11.1526 11.1394 11.2005 11.0846 11.4873 11.046C11.8137 11.0021 12.2646 11 13 11L19 11C19.5523 11 20 10.5523 20 10C20 9.44772 19.5523 9.00001 19 9.00001L12.9384 9Z" fill="#8F9AA3"/>
|
||||
<path d="M16 14C16.7354 14 17.1862 14.0021 17.5125 14.0461C17.799 14.0846 17.8468 14.1395 17.8526 14.146L17.8536 14.1471C17.8604 14.1531 17.9154 14.2016 17.954 14.4891C17.9979 14.8162 18 15.268 18 16.0043C18 16.7407 17.9979 17.1925 17.954 17.5196C17.9154 17.8071 17.8604 17.8556 17.8536 17.8616L17.8522 17.863C17.8442 17.8712 17.8181 17.8979 17.7034 17.9272C17.5612 17.9636 17.3416 17.9892 16.9698 18.0005C16.4178 18.0171 15.9838 18.4781 16.0005 19.0302C16.0171 19.5822 16.4781 20.0162 17.0302 19.9996C17.7921 19.9766 18.64 19.9045 19.2683 19.2753C19.7045 18.8385 19.8664 18.3054 19.9362 17.7857C20.0001 17.3095 20.0001 16.7211 20 16.066V15.9428C20.0001 15.2876 20.0001 14.6992 19.9362 14.223C19.8664 13.7033 19.7045 13.1702 19.2683 12.7334C18.8319 12.2964 18.299 12.1339 17.7794 12.0639C17.3036 11.9999 16.7157 11.9999 16.0617 12L16 12C15.4477 12 15 12.4477 15 13C15 13.5523 15.4477 14 16 14Z" fill="#8F9AA3"/>
|
||||
<path d="M14 13C14 12.4477 13.5523 12 13 12C12.4477 12 12 12.4477 12 13V14.5C12 15.394 12.2542 16.2178 13.0565 16.6656C13.3946 16.8543 13.7549 16.928 14.0621 16.9627C14.3698 16.9975 14.6995 17 15 17C15 17.5523 15.4477 18 16 18C16.5523 18 17 17.5523 17 17C17 15.8954 16.1046 15 15 15C14.6924 15 14.468 14.9958 14.2866 14.9753C14.152 14.9601 14.0822 14.9397 14.051 14.9279C14.0333 14.8814 14 14.7576 14 14.5V13Z" fill="#8F9AA3"/>
|
||||
<path d="M11 15.7692C11 15.217 10.5523 14.7692 10 14.7692C9.44772 14.7692 9.00001 15.217 9.00001 15.7692L9.00001 18.5385C9.00001 19.0908 9.44772 19.5385 10 19.5385C10.5523 19.5385 11 19.0908 11 18.5385L11 15.7692Z" fill="#8F9AA3"/>
|
||||
<path d="M13 18C12.4477 18 12 18.4477 12 19C12 19.5523 12.4477 20 13 20H14C14.5523 20 15 19.5523 15 19C15 18.4477 14.5523 18 14 18H13Z" fill="#8F9AA3"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.3 KiB |
@ -0,0 +1,60 @@
|
||||
import 'dart:async';
|
||||
import 'package:cloudflare_turnstile/cloudflare_turnstile.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:hmg_patient_app_new/services/logger_service.dart';
|
||||
|
||||
/// Service to handle Cloudflare Turnstile captcha verification
|
||||
class TurnstileService {
|
||||
final LoggerService _loggerService;
|
||||
|
||||
// Replace with your Cloudflare Turnstile site key
|
||||
static const String _siteKey = '0x4AAAAAAAkmbvEy63pcxBBt';
|
||||
|
||||
TurnstileService(this._loggerService);
|
||||
|
||||
/// Get Turnstile token using invisible mode
|
||||
/// Returns the token on success, null on failure
|
||||
Future<String?> getTurnstileToken() async {
|
||||
// Initialize an instance of invisible Cloudflare Turnstile with your site key
|
||||
final turnstile = CloudflareTurnstile.invisible(
|
||||
siteKey: _siteKey,
|
||||
onTimeout: () {},
|
||||
options: TurnstileOptions(
|
||||
retryInterval: const Duration(milliseconds: 2000),
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
// Get the Turnstile token
|
||||
final token = await turnstile.getToken();
|
||||
_loggerService.logInfo('Turnstile token retrieved successfully');
|
||||
return token; // Return the token upon success
|
||||
} on TurnstileException catch (e) {
|
||||
// Handle Turnstile failure
|
||||
_loggerService.logError('Turnstile challenge failed: ${e.message}');
|
||||
if (kDebugMode) {
|
||||
print('Challenge failed: ${e.message}');
|
||||
}
|
||||
} catch (e) {
|
||||
// Handle any other exceptions
|
||||
_loggerService.logError('Unexpected error during Turnstile challenge: $e');
|
||||
if (kDebugMode) {
|
||||
print('Unexpected error: $e');
|
||||
}
|
||||
} finally {
|
||||
// Ensure the Turnstile instance is properly disposed of
|
||||
turnstile.dispose();
|
||||
}
|
||||
|
||||
// Return null if the token couldn't be generated
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Get the site key for Turnstile widget
|
||||
String getSiteKey() => _siteKey;
|
||||
|
||||
/// Validate if Turnstile is properly configured
|
||||
bool isConfigured() {
|
||||
return _siteKey.isNotEmpty && _siteKey != '0x4AAAAAAAkmbvEy63pcxBBt';
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@ -1,45 +1,275 @@
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hmg_patient_app_new/core/utils/utils.dart';
|
||||
import 'package:hmg_patient_app_new/core/app_state.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/lab/lab_view_model.dart';
|
||||
import 'package:hmg_patient_app_new/features/lab/models/resp_models/lab_result.dart';
|
||||
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
||||
import 'package:hmg_patient_app_new/presentation/lab/lab_result_via_clinic/lab_order_result_item.dart';
|
||||
import 'package:provider/provider.dart' show Selector, Provider, ReadContext;
|
||||
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||
import 'package:hmg_patient_app_new/widgets/date_range_selector/viewmodel/date_range_view_model.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../../../core/dependencies.dart' show getIt;
|
||||
import '../../../core/utils/size_utils.dart' show ResponsiveExtension;
|
||||
import '../../../generated/locale_keys.g.dart' show LocaleKeys;
|
||||
|
||||
import '../../../widgets/date_range_selector/viewmodel/date_range_view_model.dart';
|
||||
class LabResultList extends StatefulWidget {
|
||||
@override
|
||||
State<LabResultList> createState() => _LabResultListState();
|
||||
}
|
||||
|
||||
class LabResultList extends StatelessWidget {
|
||||
class _LabResultListState extends State<LabResultList> {
|
||||
late LabViewModel model;
|
||||
int expandedIndex = -1;
|
||||
Map<int, bool> descriptionExpandedMap = {};
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
model = Provider.of<LabViewModel>(context);
|
||||
return Selector<LabViewModel, List<LabResult>>(
|
||||
selector: (_, model) => model.mainLabResultsByHospitals,
|
||||
builder: (__, list, ___) {
|
||||
if (list.isEmpty && context.read<LabViewModel>().labSpecialResult.isEmpty) {
|
||||
return Selector<LabViewModel, Map<String, List<LabResult>>>(
|
||||
selector: (_, model) => model.mainLabResultsByPackageName,
|
||||
builder: (__, groupedResults, ___) {
|
||||
if (groupedResults.isEmpty && context.read<LabViewModel>().labSpecialResult.isEmpty) {
|
||||
// return Utils.getNoDataWidget(context,
|
||||
// noDataText: LocaleKeys.noLabResults.tr(context: context));
|
||||
return Container();
|
||||
} else {
|
||||
// Convert map entries to a list for indexed access
|
||||
final packageEntries = groupedResults.entries.toList();
|
||||
|
||||
return ListView.builder(
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
padding: EdgeInsets.zero,
|
||||
shrinkWrap: true,itemCount: list.length,itemBuilder: (____, index) {
|
||||
var labItem = list[index];
|
||||
return LabOrderResultItem(onTap: () {
|
||||
context.read<DateRangeSelectorRangeViewModel>().flush();
|
||||
model.getPatientLabResult(model.currentlySelectedPatientOrder!, labItem.description ?? "", labItem.testShortDescription ?? "", labItem.uOM ?? "");
|
||||
},
|
||||
tests: labItem,
|
||||
index: index,
|
||||
iconColor: model.getColor(labItem.calculatedResultFlag ?? "N"),
|
||||
severityText: model.getSeverityText(labItem.calculatedResultFlag ?? "N"));
|
||||
});
|
||||
shrinkWrap: true,
|
||||
itemCount: packageEntries.length,
|
||||
itemBuilder: (context, packageIndex) {
|
||||
final packageName = packageEntries[packageIndex].key;
|
||||
final labResults = packageEntries[packageIndex].value;
|
||||
final isExpanded = expandedIndex == packageIndex;
|
||||
|
||||
return AnimatedContainer(
|
||||
duration: Duration(milliseconds: 300),
|
||||
curve: Curves.easeInOut,
|
||||
margin: EdgeInsets.symmetric(vertical: 8.h),
|
||||
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Package name as title/header
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 16.0.h),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
spacing: 8.h,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: packageName.toText18(
|
||||
isBold: true
|
||||
),
|
||||
),
|
||||
AnimatedRotation(
|
||||
turns: isExpanded ? 0.5 : 0,
|
||||
duration: Duration(milliseconds: 300),
|
||||
curve: Curves.easeInOut,
|
||||
child: Icon(Icons.expand_more),
|
||||
),
|
||||
],
|
||||
),
|
||||
if(labResults.first.packageShortDescription != null)
|
||||
_ExpandableDescriptionText(
|
||||
description: labResults.first.packageShortDescription!,
|
||||
isExpanded: descriptionExpandedMap[packageIndex] ?? false,
|
||||
onToggle: () {
|
||||
setState(() {
|
||||
descriptionExpandedMap[packageIndex] = !(descriptionExpandedMap[packageIndex] ?? false);
|
||||
});
|
||||
},
|
||||
)
|
||||
else
|
||||
SizedBox.shrink()
|
||||
],
|
||||
),),
|
||||
|
||||
// Lab results under this package with animation
|
||||
AnimatedSize(
|
||||
duration: Duration(milliseconds: 300),
|
||||
curve: Curves.easeInOut,
|
||||
child: isExpanded
|
||||
? Column(
|
||||
children: labResults.asMap().entries.map((entry) {
|
||||
final index = entry.key;
|
||||
final labItem = entry.value;
|
||||
|
||||
return TweenAnimationBuilder<double>(
|
||||
tween: Tween(begin: 0.0, end: 1.0),
|
||||
duration: Duration(milliseconds: 300 + (index * 50)),
|
||||
curve: Curves.easeOut,
|
||||
builder: (context, value, child) {
|
||||
return Opacity(
|
||||
opacity: value,
|
||||
child: Transform.translate(
|
||||
offset: Offset(0, 20 * (1 - value)),
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
LabOrderResultItem(
|
||||
onTap: () {
|
||||
context.read<DateRangeSelectorRangeViewModel>().flush();
|
||||
model.getPatientLabResult(
|
||||
model.currentlySelectedPatientOrder!,
|
||||
labItem.description ?? "",
|
||||
labItem.testShortDescription ?? "",
|
||||
labItem.uOM ?? ""
|
||||
);
|
||||
},
|
||||
tests: labItem,
|
||||
index: index,
|
||||
iconColor: model.getColor(labItem.calculatedResultFlag ?? "N"),
|
||||
severityText: model.getSeverityText(labItem.calculatedResultFlag ?? "N")
|
||||
),
|
||||
if(labResults.length>1)
|
||||
...[SizedBox(
|
||||
height: 8.h,
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.h),
|
||||
child: Divider(
|
||||
color: AppColors.dividerColor,
|
||||
thickness: 1.h,
|
||||
),
|
||||
)]
|
||||
],
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
)
|
||||
: SizedBox.shrink(),
|
||||
),
|
||||
],
|
||||
),
|
||||
).onPress((){
|
||||
setState(() {
|
||||
expandedIndex = isExpanded ? -1 : packageIndex;
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ExpandableDescriptionText extends StatelessWidget {
|
||||
final String description;
|
||||
final bool isExpanded;
|
||||
final VoidCallback onToggle;
|
||||
|
||||
const _ExpandableDescriptionText({
|
||||
required this.description,
|
||||
required this.isExpanded,
|
||||
required this.onToggle,
|
||||
});
|
||||
|
||||
static TextStyle get textStyle => TextStyle(
|
||||
fontSize: 14.f,
|
||||
color: AppColors.textColorLight,
|
||||
// or Colors.black87
|
||||
// fontFamily: 'Poppins',
|
||||
fontWeight: FontWeight.w600,
|
||||
fontStyle: FontStyle.normal,
|
||||
height: 1.4,
|
||||
letterSpacing: 0.0,
|
||||
decoration: TextDecoration.none,
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final readMoreText = isExpanded
|
||||
? ' ${LocaleKeys.hide.tr()}'
|
||||
: ' ${LocaleKeys.readMore.tr(context: context)}';
|
||||
|
||||
final readMoreStyle = TextStyle(
|
||||
fontSize: 12.f,
|
||||
color: AppColors.primaryRedColor,
|
||||
// fontFamily: 'Poppins',
|
||||
fontWeight: FontWeight.w500,
|
||||
);
|
||||
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
// Check if description alone overflows 2 lines
|
||||
final descriptionPainter = TextPainter(
|
||||
text: TextSpan(text: description, style: textStyle),
|
||||
maxLines: 2,
|
||||
textDirection: Directionality.of(context),
|
||||
)..layout(maxWidth: constraints.maxWidth);
|
||||
|
||||
final isOverflowing = descriptionPainter.didExceedMaxLines;
|
||||
|
||||
// No overflow, or already expanded -> show full text
|
||||
if (!isOverflowing || isExpanded) {
|
||||
return GestureDetector(
|
||||
onTap: isOverflowing ? onToggle : null,
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
style: textStyle,
|
||||
children: [
|
||||
TextSpan(text: description, style: textStyle),
|
||||
if (isOverflowing)
|
||||
TextSpan(text: readMoreText, style: readMoreStyle),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Binary search for max chars that fit in 2 lines with "Read more" appended
|
||||
int low = 0, high = description.length;
|
||||
while (low < high) {
|
||||
final mid = (low + high + 1) ~/ 2;
|
||||
final testPainter = TextPainter(
|
||||
text: TextSpan(
|
||||
style: textStyle,
|
||||
children: [
|
||||
TextSpan(text: '${description.substring(0, mid)}...'),
|
||||
TextSpan(text: readMoreText, style: readMoreStyle),
|
||||
],
|
||||
),
|
||||
maxLines: 2,
|
||||
textDirection: Directionality.of(context),
|
||||
)..layout(maxWidth: constraints.maxWidth);
|
||||
|
||||
if (testPainter.didExceedMaxLines) {
|
||||
high = mid - 1;
|
||||
} else {
|
||||
low = mid;
|
||||
}
|
||||
}
|
||||
|
||||
final truncated = description.substring(0, low).trimRight();
|
||||
|
||||
return GestureDetector(
|
||||
onTap: onToggle,
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
style: textStyle,
|
||||
children: [
|
||||
TextSpan(text: '$truncated...'),
|
||||
TextSpan(text: readMoreText, style: readMoreStyle),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hmg_patient_app_new/core/app_assets.dart';
|
||||
import 'package:hmg_patient_app_new/core/app_state.dart';
|
||||
import 'package:hmg_patient_app_new/core/dependencies.dart';
|
||||
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
|
||||
import 'package:hmg_patient_app_new/extensions/string_extensions.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 '../../../generated/locale_keys.g.dart';
|
||||
|
||||
class PatientQrCodeWidget extends StatelessWidget {
|
||||
PatientQrCodeWidget({super.key});
|
||||
|
||||
late AppState appState;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
appState = getIt.get<AppState>();
|
||||
return Column(
|
||||
children: [
|
||||
SizedBox(height: 8.h),
|
||||
"${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}".toText18(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 2),
|
||||
SizedBox(height: 8.h),
|
||||
Wrap(
|
||||
direction: Axis.horizontal,
|
||||
spacing: 4.w,
|
||||
runSpacing: 6.w,
|
||||
children: [
|
||||
AppCustomChipWidget(
|
||||
icon: AppAssets.file_icon,
|
||||
labelText: "${LocaleKeys.fileno.tr(context: context)}: ${appState.getAuthenticatedUser()!.patientId}",
|
||||
labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w),
|
||||
),
|
||||
AppCustomChipWidget(
|
||||
icon: AppAssets.checkmark_icon,
|
||||
labelText: LocaleKeys.verified.tr(context: context),
|
||||
iconColor: AppColors.successColor,
|
||||
labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 16.h),
|
||||
Image.network(
|
||||
"https://api.qrserver.com/v1/create-qr-code/?size=250x250&data=${appState.getAuthenticatedUser()!.patientId.toString()}",
|
||||
fit: BoxFit.fill,
|
||||
height: 156.h,
|
||||
width: 156.h,
|
||||
),
|
||||
SizedBox(height: 16.h),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue