@ -0,0 +1,194 @@
|
||||
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/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/weather/weather_view_model.dart';
|
||||
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
||||
import 'package:hmg_patient_app_new/presentation/weather/weather_details_page.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/routes/custom_page_route.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class WeatherWidget extends StatelessWidget {
|
||||
final bool showButton;
|
||||
|
||||
const WeatherWidget({super.key, this.showButton = true});
|
||||
|
||||
String _getWeatherIcon(String? categoryValue) {
|
||||
if (categoryValue == null) return "assets/images/svg/cloudyweather.svg";
|
||||
|
||||
final lowerValue = categoryValue.toLowerCase();
|
||||
if (lowerValue.contains('sunny') || lowerValue.contains('clear')) {
|
||||
return "assets/images/svg/morning.svg";
|
||||
} else if (lowerValue.contains('cloudy') || lowerValue.contains('cloud')) {
|
||||
return "assets/images/svg/cloudyweather.svg";
|
||||
} else if (lowerValue.contains('rain')) {
|
||||
return "assets/images/svg/cloudyweather.svg";
|
||||
}
|
||||
return "assets/images/svg/cloudyweather.svg";
|
||||
}
|
||||
|
||||
String _formatDateTime(DateTime dateTime) {
|
||||
final formatter = DateFormat('MMMM dd, yyyy - EEEE, HH:mm');
|
||||
return formatter.format(dateTime);
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Consumer<WeatherMonitorViewModel>(
|
||||
builder: (context, weatherVM, child) {
|
||||
final currentCity = weatherVM.cityInfoList.isNotEmpty
|
||||
? weatherVM.cityInfoList.first
|
||||
: null;
|
||||
|
||||
final now = DateTime.now();
|
||||
final temperature = currentCity?.temperature;
|
||||
final healthTip = LocaleKeys.healthTipsBasedOnCurrentWeather.tr();
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(16.w),
|
||||
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||
color: AppColors.whiteColor,
|
||||
borderRadius: 24.r,
|
||||
hasShadow: false,
|
||||
),
|
||||
child: weatherVM.isLoading
|
||||
? _buildLoadingState()
|
||||
: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Utils.buildSvgWithAssets(
|
||||
icon: _getWeatherIcon(currentCity?.categoryValue),
|
||||
width: 64.w,
|
||||
height: 64.w,
|
||||
),
|
||||
SizedBox(width: 12.w),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_formatDateTime(now).toText12(
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.greyTextColor,
|
||||
),
|
||||
SizedBox(height: 4.w),
|
||||
"$temperature°C"
|
||||
.toText16(
|
||||
isBold: true,
|
||||
weight: FontWeight.w600,
|
||||
),
|
||||
SizedBox(height: 4.w),
|
||||
healthTip.toText12(
|
||||
color: AppColors.greyTextColor,
|
||||
fontWeight: FontWeight.w500,
|
||||
maxLine: 2,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (showButton) ...[
|
||||
SizedBox(height: 16.w),
|
||||
CustomButton(
|
||||
text: LocaleKeys.viewDetails.tr(context: context),
|
||||
onPressed: () {
|
||||
Navigator.of(context).push(
|
||||
CustomPageRoute(
|
||||
page: ChangeNotifierProvider.value(
|
||||
value: weatherVM,
|
||||
child: const WeatherDetailsPage(),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
padding: EdgeInsets.zero,
|
||||
backgroundColor: AppColors.secondaryLightRedColor,
|
||||
borderColor: AppColors.secondaryLightRedColor,
|
||||
textColor: AppColors.primaryRedColor,
|
||||
fontSize: 14.f,
|
||||
fontWeight: FontWeight.w600,
|
||||
borderRadius: 10.r,
|
||||
height: 40.h,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
).paddingSymmetrical(24.w, 0.w);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLoadingState() {
|
||||
return Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 64.w,
|
||||
height: 64.w,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.lightGrayBGColor,
|
||||
borderRadius: BorderRadius.circular(12.r),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 12.w),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 12.h,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.lightGrayBGColor,
|
||||
borderRadius: BorderRadius.circular(6.r),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8.h),
|
||||
Container(
|
||||
width: 100.w,
|
||||
height: 16.h,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.lightGrayBGColor,
|
||||
borderRadius: BorderRadius.circular(8.r),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8.h),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 12.h,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.lightGrayBGColor,
|
||||
borderRadius: BorderRadius.circular(6.r),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 16.w),
|
||||
Container(
|
||||
height: 56.h,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.lightGrayBGColor,
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,185 @@
|
||||
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/core/app_state.dart';
|
||||
import 'package:hmg_patient_app_new/core/dependencies.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/weather/models/waether_cities_model.dart';
|
||||
import 'package:hmg_patient_app_new/features/weather/weather_view_model.dart';
|
||||
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
||||
import 'package:hmg_patient_app_new/presentation/hmg_services/widgets/weather_widget.dart';
|
||||
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class WeatherDetailsPage extends StatelessWidget {
|
||||
const WeatherDetailsPage({super.key});
|
||||
|
||||
Color _getColorFromColorName(ColorName? colorName) {
|
||||
if (colorName == null) return AppColors.successColor;
|
||||
|
||||
switch (colorName) {
|
||||
case ColorName.GREEN:
|
||||
return AppColors.successColor;
|
||||
case ColorName.ORANGE:
|
||||
return AppColors.warningColor;
|
||||
case ColorName.RED:
|
||||
return AppColors.errorColor;
|
||||
}
|
||||
}
|
||||
|
||||
Color _getBackgroundColorFromColorName(ColorName? colorName) {
|
||||
if (colorName == null) return AppColors.successLightColor.withValues(alpha: 0.1);
|
||||
|
||||
switch (colorName) {
|
||||
case ColorName.GREEN:
|
||||
return AppColors.successLightColor.withValues(alpha: 0.1);
|
||||
case ColorName.ORANGE:
|
||||
return AppColors.warningLightColor.withValues(alpha: 0.1);
|
||||
case ColorName.RED:
|
||||
return AppColors.errorLightColor.withValues(alpha: 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
IconData _getIconFromCategory(String? category) {
|
||||
if (category == null) return Icons.wb_sunny_outlined;
|
||||
|
||||
final lowerCategory = category.toLowerCase();
|
||||
if (lowerCategory.contains('walking') || lowerCategory.contains('activity')) {
|
||||
return Icons.directions_walk;
|
||||
} else if (lowerCategory.contains('weather') || lowerCategory.contains('temperature')) {
|
||||
return Icons.thermostat_outlined;
|
||||
} else if (lowerCategory.contains('elderly') || lowerCategory.contains('hiking')) {
|
||||
return Icons.elderly;
|
||||
}
|
||||
return Icons.wb_sunny_outlined;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Consumer<WeatherMonitorViewModel>(
|
||||
builder: (context, weatherVM, child) {
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.bgScaffoldColor,
|
||||
body: CollapsingListView(
|
||||
title: LocaleKeys.healthWeatherIndicators.tr(),
|
||||
isLeading: true,
|
||||
child: weatherVM.isLoading
|
||||
? Center(
|
||||
child: CircularProgressIndicator(
|
||||
color: AppColors.primaryRedColor,
|
||||
),
|
||||
)
|
||||
: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Reuse WeatherWidget at the top (without the button)
|
||||
const WeatherWidget(showButton: false),
|
||||
|
||||
SizedBox(height: 16.h),
|
||||
|
||||
// Categories List (Sliders)
|
||||
...weatherVM.cityInfoList.map((cityInfo) {
|
||||
return _buildCategoryCard(
|
||||
description: cityInfo.name ?? '',
|
||||
categoryLabel: cityInfo.category ?? '',
|
||||
color: _getColorFromColorName(cityInfo.colorName),
|
||||
backgroundColor: _getBackgroundColorFromColorName(cityInfo.colorName),
|
||||
icon: _getIconFromCategory(cityInfo.category),
|
||||
);
|
||||
}),
|
||||
|
||||
SizedBox(height: 24.h),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCategoryCard({
|
||||
required String description,
|
||||
required String categoryLabel,
|
||||
required Color color,
|
||||
required Color backgroundColor,
|
||||
required IconData icon,
|
||||
}) {
|
||||
return Container(
|
||||
margin: EdgeInsets.only(bottom: 16.h),
|
||||
padding: EdgeInsets.all(16.w),
|
||||
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||
color: AppColors.whiteColor,
|
||||
borderRadius: 16.r,
|
||||
hasShadow: false,
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Icon
|
||||
Container(
|
||||
width: 40.w,
|
||||
height: 40.w,
|
||||
decoration: BoxDecoration(
|
||||
color: backgroundColor,
|
||||
borderRadius: BorderRadius.circular(8.r),
|
||||
),
|
||||
child: Icon(
|
||||
icon,
|
||||
color: color,
|
||||
size: 24.w,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 12.w),
|
||||
// Content
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
description.toText14(
|
||||
isBold: true,
|
||||
color: AppColors.textColor,
|
||||
),
|
||||
SizedBox(height: 8.h),
|
||||
// Progress bar
|
||||
Container(
|
||||
height: 4.h,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.lightGrayBGColor,
|
||||
borderRadius: BorderRadius.circular(2.r),
|
||||
),
|
||||
child: FractionallySizedBox(
|
||||
alignment: Alignment.centerLeft,
|
||||
widthFactor: 0.7,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: color,
|
||||
borderRadius: BorderRadius.circular(2.r),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(width: 12.w),
|
||||
// Category Label
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h),
|
||||
decoration: BoxDecoration(
|
||||
color: backgroundColor,
|
||||
borderRadius: BorderRadius.circular(8.r),
|
||||
),
|
||||
child: categoryLabel.toText12(
|
||||
color: color,
|
||||
fontWeight: FontWeight.w600,
|
||||
maxLine: 1
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
).paddingSymmetrical(24.w, 0.w);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue