Compare commits
7 Commits
a1beacc36e
...
00475dc100
| Author | SHA1 | Date |
|---|---|---|
|
|
00475dc100 | 5 hours ago |
|
|
23b92cef41 | 5 hours ago |
|
|
3ff9628cd3 | 5 hours ago |
|
|
7d8537fae6 | 8 hours ago |
|
|
1edeff439e | 8 hours ago |
|
|
8b5c4d7575 | 1 day ago |
|
|
8c92df8648 | 1 day ago |
File diff suppressed because one or more lines are too long
@ -1,310 +0,0 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hmg_patient_app_new/core/app_export.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/monthly_reports/monthly_reports_view_model.dart';
|
||||
import 'package:hmg_patient_app_new/presentation/monthly_reports/user_agreement_page.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../generated/locale_keys.g.dart';
|
||||
import '../../theme/colors.dart';
|
||||
import '../../widgets/appbar/app_bar_widget.dart';
|
||||
import '../../widgets/input_widget.dart';
|
||||
import '../../widgets/loader/bottomsheet_loader.dart';
|
||||
|
||||
class MonthlyReportsPage extends StatefulWidget {
|
||||
const MonthlyReportsPage({super.key});
|
||||
|
||||
@override
|
||||
State<MonthlyReportsPage> createState() => _MonthlyReportsPageState();
|
||||
}
|
||||
|
||||
class _MonthlyReportsPageState extends State<MonthlyReportsPage> {
|
||||
bool isHealthSummaryEnabled = false;
|
||||
bool isTermsAccepted = false;
|
||||
|
||||
final TextEditingController emailController = TextEditingController();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
emailController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _showError(String message) {
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(message),
|
||||
behavior: SnackBarBehavior.floating,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showSuccessSnackBar() {
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
"Successfully updated".needTranslation,
|
||||
style: const TextStyle(
|
||||
color: AppColors.whiteColor,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
behavior: SnackBarBehavior.floating,
|
||||
backgroundColor: AppColors.textGreenColor,
|
||||
duration: const Duration(seconds: 2),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onSavePressed() async {
|
||||
if (!isTermsAccepted) {
|
||||
_showError("Please accept the terms and conditions".needTranslation);
|
||||
return;
|
||||
}
|
||||
|
||||
final email = emailController.text.trim();
|
||||
if (email.isEmpty) {
|
||||
_showError("Please enter your email".needTranslation);
|
||||
return;
|
||||
}
|
||||
|
||||
final vm = context.read<MonthlyReportsViewModel>();
|
||||
|
||||
// LoaderBottomSheet.showLoader();
|
||||
final ok = await vm.saveMonthlyReport(email: email);
|
||||
// LoaderBottomSheet.hideLoader();
|
||||
|
||||
if (ok) {
|
||||
setState(() => isHealthSummaryEnabled = true);
|
||||
_showSuccessSnackBar();
|
||||
} else {
|
||||
// _showError("Failed to update".needTranslation);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.scaffoldBgColor,
|
||||
appBar: CustomAppBar(
|
||||
onBackPressed: () => Navigator.of(context).pop(),
|
||||
onLanguageChanged: (_) {},
|
||||
hideLogoAndLang: true,
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Monthly Reports".needTranslation,
|
||||
style: TextStyle(
|
||||
color: AppColors.textColor,
|
||||
fontSize: 27.f,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16.h),
|
||||
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 8.h),
|
||||
height: 54.h,
|
||||
alignment: Alignment.center,
|
||||
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||
color: AppColors.whiteColor,
|
||||
borderRadius: (12.r),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Patient Health Summary Report".needTranslation,
|
||||
style: TextStyle(
|
||||
color: AppColors.textColor,
|
||||
fontSize: 14.f,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
_buildToggle(),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(height: 16.h),
|
||||
|
||||
TextInputWidget(
|
||||
controller: emailController,
|
||||
labelText: "Eamil*".needTranslation,
|
||||
hintText: "email@email.com",
|
||||
isEnable: true,
|
||||
prefix: null,
|
||||
isAllowRadius: true,
|
||||
isBorderAllowed: false,
|
||||
isAllowLeadingIcon: true,
|
||||
autoFocus: true,
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 8.h),
|
||||
onChange: (value) {
|
||||
setState(() {});
|
||||
},
|
||||
).paddingOnly(top: 8.h, bottom: 8.h),
|
||||
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
"To View The Terms and Conditions".needTranslation,
|
||||
style: TextStyle(
|
||||
color: AppColors.textColor,
|
||||
fontSize: 14.f,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
InkWell(
|
||||
child: Text(
|
||||
"Click here".needTranslation,
|
||||
style: TextStyle(
|
||||
color: AppColors.primaryRedColor,
|
||||
fontSize: 14.f,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => const UserAgreementPage(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
SizedBox(height: 12.h),
|
||||
|
||||
GestureDetector(
|
||||
onTap: () => setState(() => isTermsAccepted = !isTermsAccepted),
|
||||
child: Row(
|
||||
children: [
|
||||
AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
height: 24.h,
|
||||
width: 24.h,
|
||||
decoration: BoxDecoration(
|
||||
color: isTermsAccepted
|
||||
? AppColors.textGreenColor
|
||||
: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
border: Border.all(
|
||||
color: isTermsAccepted
|
||||
? AppColors.lightGreenColor
|
||||
: AppColors.greyColor,
|
||||
width: 2.h,
|
||||
),
|
||||
),
|
||||
child: isTermsAccepted
|
||||
? Icon(Icons.check, size: 16.f, color: AppColors.whiteColor,)
|
||||
: null,
|
||||
),
|
||||
SizedBox(width: 12.h),
|
||||
Text(
|
||||
"I agree to the terms and conditions".needTranslation,
|
||||
style: context.dynamicTextStyle(
|
||||
fontSize: 12.f,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.textColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(height: 12.h),
|
||||
|
||||
Text(
|
||||
"This monthly Health Summary Report reflects the health indicators and analysis results of the latest visits. Please note that this will be sent automatically from the system and it's not considered as an official report so no medical decisions should be taken based on it"
|
||||
.needTranslation,
|
||||
style: TextStyle(
|
||||
color: AppColors.textColor,
|
||||
fontSize: 10.f,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(height: 12.h),
|
||||
|
||||
Image.asset('assets/images/jpg/report.jpg'),
|
||||
|
||||
SizedBox(height: 16.h),
|
||||
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppColors.successColor,
|
||||
foregroundColor: AppColors.whiteColor,
|
||||
elevation: 0,
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
onPressed: _onSavePressed,
|
||||
child: Text(
|
||||
LocaleKeys.save.tr(),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 16.f,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
).paddingAll(16),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildToggle() {
|
||||
final value = isHealthSummaryEnabled;
|
||||
|
||||
return AbsorbPointer(
|
||||
absorbing: true,
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
width: 50.h,
|
||||
height: 28.h,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: value
|
||||
? AppColors.lightGreenColor
|
||||
: AppColors.greyColor.withOpacity(0.3),
|
||||
),
|
||||
child: AnimatedAlign(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
alignment: value ? Alignment.centerRight : Alignment.centerLeft,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(3),
|
||||
child: Container(
|
||||
width: 22.h,
|
||||
height: 22.h,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: value
|
||||
? AppColors.textGreenColor
|
||||
: AppColors.greyTextColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,117 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
|
||||
import 'package:hmg_patient_app_new/features/monthly_reports/terms_conditions_view_model.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:webview_flutter/webview_flutter.dart';
|
||||
|
||||
import '../../theme/colors.dart';
|
||||
import '../../widgets/appbar/app_bar_widget.dart';
|
||||
|
||||
class UserAgreementPage extends StatefulWidget {
|
||||
const UserAgreementPage({super.key});
|
||||
|
||||
@override
|
||||
State<UserAgreementPage> createState() => _UserAgreementPageState();
|
||||
}
|
||||
|
||||
class _UserAgreementPageState extends State<UserAgreementPage> {
|
||||
late final WebViewController _webViewController;
|
||||
bool _isLoading = true;
|
||||
String? _errorMessage;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_webViewController = WebViewController()
|
||||
..setJavaScriptMode(JavaScriptMode.unrestricted)
|
||||
..setBackgroundColor(const Color(0x00000000))
|
||||
..setNavigationDelegate(
|
||||
NavigationDelegate(
|
||||
onPageStarted: (_) {
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
},
|
||||
onPageFinished: (_) {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
},
|
||||
onWebResourceError: (error) {
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
final vm =
|
||||
Provider.of<TermsConditionsViewModel>(context, listen: false);
|
||||
|
||||
vm.getTermsConditions(
|
||||
onSuccess: () {
|
||||
final htmlString = vm.termsConditionsHtml ?? '';
|
||||
|
||||
if (htmlString.isNotEmpty) {
|
||||
setState(() {
|
||||
_errorMessage = null;
|
||||
_isLoading = true;
|
||||
});
|
||||
_webViewController.loadHtmlString(htmlString);
|
||||
} else {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
_errorMessage = 'لا توجد شروط متاحة حالياً'.needTranslation;
|
||||
});
|
||||
}
|
||||
},
|
||||
onError: (msg) {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
_errorMessage = msg;
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.scaffoldBgColor,
|
||||
appBar: CustomAppBar(
|
||||
onBackPressed: () => Navigator.of(context).pop(),
|
||||
onLanguageChanged: (_) {},
|
||||
hideLogoAndLang: true,
|
||||
),
|
||||
body: Stack(
|
||||
children: [
|
||||
WebViewWidget(controller: _webViewController),
|
||||
|
||||
if (_errorMessage != null)
|
||||
Center(
|
||||
child: Container(
|
||||
margin: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.whiteColor,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
_errorMessage!,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: AppColors.primaryRedColor,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (_isLoading)
|
||||
const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,284 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hmg_patient_app_new/core/utils/date_util.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/extensions/widget_extensions.dart';
|
||||
import 'package:hmg_patient_app_new/features/notifications/models/resp_models/notification_response_model.dart';
|
||||
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
|
||||
class NotificationDetailsPage extends StatelessWidget {
|
||||
final NotificationResponseModel notification;
|
||||
|
||||
const NotificationDetailsPage({
|
||||
super.key,
|
||||
required this.notification,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Debug logging
|
||||
print('=== Notification Details ===');
|
||||
print('Message: ${notification.message}');
|
||||
print('MessageType: ${notification.messageType}');
|
||||
print('MessageTypeData: ${notification.messageTypeData}');
|
||||
print('VideoURL: ${notification.videoURL}');
|
||||
print('========================');
|
||||
|
||||
return CollapsingListView(
|
||||
title: "Notification Details".needTranslation,
|
||||
trailing: IconButton(
|
||||
icon: Icon(
|
||||
Icons.share_outlined,
|
||||
size: 24.h,
|
||||
color: AppColors.textColor,
|
||||
),
|
||||
onPressed: () {
|
||||
_shareNotification();
|
||||
},
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(height: 24.h),
|
||||
// Notification content card
|
||||
_buildNotificationCard(context),
|
||||
SizedBox(height: 24.h),
|
||||
],
|
||||
).paddingSymmetrical(24.w, 0.h),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildNotificationCard(BuildContext context) {
|
||||
return Container(
|
||||
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||
color: AppColors.whiteColor,
|
||||
borderRadius: 24.h,
|
||||
hasShadow: true,
|
||||
),
|
||||
padding: EdgeInsets.all(16.h),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Date and Time row
|
||||
Row(
|
||||
children: [
|
||||
// Time chip with clock icon
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.greyColor,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(Icons.access_time, size: 12.w, color: AppColors.textColor),
|
||||
SizedBox(width: 4.w),
|
||||
_formatTime(notification.isSentOn).toText10(
|
||||
weight: FontWeight.w500,
|
||||
color: AppColors.textColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8.w),
|
||||
// Date chip with calendar icon
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.greyColor,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(Icons.calendar_today, size: 12.w, color: AppColors.textColor),
|
||||
SizedBox(width: 4.w),
|
||||
_formatDate(notification.isSentOn).toText10(
|
||||
weight: FontWeight.w500,
|
||||
color: AppColors.textColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 16.h),
|
||||
|
||||
// Notification message
|
||||
if (notification.message != null && notification.message!.isNotEmpty)
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
'Message'.needTranslation.toText14(
|
||||
weight: FontWeight.w600,
|
||||
color: AppColors.greyTextColor,
|
||||
),
|
||||
SizedBox(height: 8.h),
|
||||
notification.message!.toText16(
|
||||
weight: FontWeight.w400,
|
||||
color: AppColors.textColor,
|
||||
maxlines: 100,
|
||||
),
|
||||
SizedBox(height: 16.h),
|
||||
],
|
||||
),
|
||||
|
||||
// Notification image (if MessageType is "image")
|
||||
if (notification.messageType != null &&
|
||||
notification.messageType!.toLowerCase() == "image")
|
||||
Builder(
|
||||
builder: (context) {
|
||||
// Try to get image URL from videoURL or messageTypeData
|
||||
String? imageUrl;
|
||||
|
||||
if (notification.videoURL != null && notification.videoURL!.isNotEmpty) {
|
||||
imageUrl = notification.videoURL;
|
||||
print('Image URL from videoURL: $imageUrl');
|
||||
} else if (notification.messageTypeData != null && notification.messageTypeData!.isNotEmpty) {
|
||||
imageUrl = notification.messageTypeData;
|
||||
print('Image URL from messageTypeData: $imageUrl');
|
||||
}
|
||||
|
||||
if (imageUrl == null || imageUrl.isEmpty) {
|
||||
print('No image URL found. videoURL: ${notification.videoURL}, messageTypeData: ${notification.messageTypeData}');
|
||||
return SizedBox.shrink();
|
||||
}
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
'Attached Image'.needTranslation.toText14(
|
||||
weight: FontWeight.w600,
|
||||
color: AppColors.greyTextColor,
|
||||
),
|
||||
SizedBox(height: 8.h),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12.h),
|
||||
child: Image.network(
|
||||
imageUrl,
|
||||
width: double.infinity,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
print('Error loading image: $error');
|
||||
print('Image URL: $imageUrl');
|
||||
return Container(
|
||||
height: 200.h,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.greyColor.withValues(alpha: 0.2),
|
||||
borderRadius: BorderRadius.circular(12.h),
|
||||
),
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.broken_image_outlined,
|
||||
size: 48.h,
|
||||
color: AppColors.greyTextColor,
|
||||
),
|
||||
SizedBox(height: 8.h),
|
||||
'Failed to load image'.needTranslation.toText12(
|
||||
color: AppColors.greyTextColor,
|
||||
),
|
||||
SizedBox(height: 4.h),
|
||||
Text(
|
||||
imageUrl!,
|
||||
style: TextStyle(fontSize: 8, color: AppColors.greyTextColor),
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
loadingBuilder: (context, child, loadingProgress) {
|
||||
if (loadingProgress == null) {
|
||||
print('Image loaded successfully');
|
||||
return child;
|
||||
}
|
||||
return Container(
|
||||
height: 200.h,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.greyColor.withValues(alpha: 0.2),
|
||||
borderRadius: BorderRadius.circular(12.h),
|
||||
),
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(
|
||||
value: loadingProgress.expectedTotalBytes != null
|
||||
? loadingProgress.cumulativeBytesLoaded /
|
||||
loadingProgress.expectedTotalBytes!
|
||||
: null,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16.h),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
// Additional notification info
|
||||
if (notification.notificationType != null && notification.notificationType!.isNotEmpty)
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
'Type'.needTranslation.toText14(
|
||||
weight: FontWeight.w600,
|
||||
color: AppColors.greyTextColor,
|
||||
),
|
||||
SizedBox(height: 8.h),
|
||||
notification.notificationType!.toText16(
|
||||
weight: FontWeight.w400,
|
||||
color: AppColors.textColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _shareNotification() async {
|
||||
final String shareText = '''
|
||||
${notification.message ?? 'Notification'}
|
||||
|
||||
Time: ${_formatTime(notification.isSentOn)}
|
||||
Date: ${_formatDate(notification.isSentOn)}
|
||||
${notification.notificationType != null ? '\nType: ${notification.notificationType}' : ''}
|
||||
'''.trim();
|
||||
|
||||
await Share.share(shareText);
|
||||
}
|
||||
|
||||
String _formatTime(String? dateTimeString) {
|
||||
if (dateTimeString == null || dateTimeString.isEmpty) return '--';
|
||||
try {
|
||||
final dateTime = DateUtil.convertStringToDate(dateTimeString);
|
||||
return DateFormat('hh:mm a').format(dateTime);
|
||||
} catch (e) {
|
||||
return '--';
|
||||
}
|
||||
}
|
||||
|
||||
String _formatDate(String? dateTimeString) {
|
||||
if (dateTimeString == null || dateTimeString.isEmpty) return '--';
|
||||
try {
|
||||
final dateTime = DateUtil.convertStringToDate(dateTimeString);
|
||||
return DateFormat('dd MMM yyyy').format(dateTime);
|
||||
} catch (e) {
|
||||
return '--';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue