|
|
import 'dart:math';
|
|
|
|
|
|
import 'package:fl_chart/fl_chart.dart';
|
|
|
import 'package:flutter/material.dart';
|
|
|
import 'package:hmg_patient_app_new/core/app_export.dart';
|
|
|
import 'package:hmg_patient_app_new/core/common_models/data_points.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/generated/locale_keys.g.dart';
|
|
|
import 'package:hmg_patient_app_new/theme/colors.dart';
|
|
|
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
|
|
|
import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart';
|
|
|
import 'package:hmg_patient_app_new/widgets/graph/CustomBarGraph.dart';
|
|
|
import 'package:intl/intl.dart' show DateFormat;
|
|
|
|
|
|
class ActivityDetails extends StatefulWidget {
|
|
|
final String selectedActivity;
|
|
|
|
|
|
const ActivityDetails({super.key, required this.selectedActivity});
|
|
|
|
|
|
@override
|
|
|
State<ActivityDetails> createState() => _ActivityDetailsState();
|
|
|
}
|
|
|
|
|
|
class _ActivityDetailsState extends State<ActivityDetails> {
|
|
|
int index = 0;
|
|
|
|
|
|
@override
|
|
|
Widget build(BuildContext context) {
|
|
|
return Scaffold(
|
|
|
backgroundColor: AppColors.bgScaffoldColor,
|
|
|
body: CollapsingListView(
|
|
|
title: "All Health Data".needTranslation,
|
|
|
child: Column(
|
|
|
spacing: 16.h,
|
|
|
children: [
|
|
|
periodSelectorView((index) {}),
|
|
|
activityDetails(),
|
|
|
DecoratedBox(
|
|
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 12.h),
|
|
|
child:
|
|
|
activityGraph().paddingOnly(left: 16.w, right: 16.w, top: 32.h, bottom: 16.h),)
|
|
|
],
|
|
|
).paddingSymmetrical(24.w, 24.h),
|
|
|
),
|
|
|
);
|
|
|
}
|
|
|
|
|
|
Widget periodSelectorView(Function(int) onItemSelected) {
|
|
|
return DecoratedBox(
|
|
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 12.h),
|
|
|
child: Row(
|
|
|
children: [
|
|
|
Expanded(
|
|
|
child: CustomTabBar(
|
|
|
activeTextColor: Color(0xffED1C2B),
|
|
|
activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1),
|
|
|
tabs: [
|
|
|
CustomTabBarModel(null, "D"),
|
|
|
CustomTabBarModel(null, "W"),
|
|
|
CustomTabBarModel(null, "M"),
|
|
|
CustomTabBarModel(null, "6M"),
|
|
|
CustomTabBarModel(null, "Y"),
|
|
|
// CustomTabBarModel(null, "Completed".needTranslation),
|
|
|
],
|
|
|
shouldTabExpanded: true,
|
|
|
onTabChange: (index) {
|
|
|
//todo handle the selection from viewmodel
|
|
|
setState(() {
|
|
|
this.index = index;
|
|
|
});
|
|
|
},
|
|
|
),
|
|
|
),
|
|
|
],
|
|
|
).paddingSymmetrical(4.w, 4.h));
|
|
|
}
|
|
|
|
|
|
Widget activityDetails() {
|
|
|
return DecoratedBox(
|
|
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 12.h, hasShadow: true),
|
|
|
child: Column(
|
|
|
spacing: 8.h,
|
|
|
children: [
|
|
|
Column(
|
|
|
children: [widget.selectedActivity.toText32(weight: FontWeight.w600, color: AppColors.textColor), "Average".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor)],
|
|
|
),
|
|
|
Row(
|
|
|
children: ["3232".toText24(color: AppColors.textGreenColor, fontWeight: FontWeight.w600), "(20-21)".toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500)],
|
|
|
)
|
|
|
],
|
|
|
).paddingSymmetrical(16.w, 16.h));
|
|
|
}
|
|
|
|
|
|
|
|
|
Widget activityGraph() {
|
|
|
final _random = Random();
|
|
|
|
|
|
int randomBP() => 100 + _random.nextInt(51); // 100–150
|
|
|
final List<DataPoint> data6Months = List.generate(6, (index) {
|
|
|
final date = DateTime.now().subtract(Duration(days: 30 * (5 - index)));
|
|
|
|
|
|
final value = randomBP();
|
|
|
|
|
|
return DataPoint(
|
|
|
value: value.toDouble(),
|
|
|
label: value.toString(),
|
|
|
actualValue: value.toString(),
|
|
|
displayTime: DateFormat('MMM').format(date),
|
|
|
unitOfMeasurement: 'mmHg',
|
|
|
time: date,
|
|
|
);
|
|
|
});
|
|
|
final List<DataPoint> data12Months = List.generate(12, (index) {
|
|
|
final date = DateTime.now().subtract(Duration(days: 30 * (11 - index)));
|
|
|
|
|
|
final value = randomBP();
|
|
|
|
|
|
return DataPoint(
|
|
|
value: value.toDouble(),
|
|
|
label: value.toString(),
|
|
|
actualValue: value.toString(),
|
|
|
displayTime: DateFormat('MMM').format(date),
|
|
|
unitOfMeasurement: 'mmHg',
|
|
|
time: date,
|
|
|
);
|
|
|
});
|
|
|
|
|
|
List<DataPoint> data =[];
|
|
|
if(index == 0){
|
|
|
data = data6Months;
|
|
|
} else if(index == 1){
|
|
|
data = data12Months;
|
|
|
} else
|
|
|
data = [
|
|
|
DataPoint(
|
|
|
value: 128,
|
|
|
label: "128",
|
|
|
actualValue: '128',
|
|
|
displayTime: 'Sun',
|
|
|
unitOfMeasurement: 'mmHg',
|
|
|
time: DateTime.now().subtract(const Duration(days: 6)),
|
|
|
),
|
|
|
DataPoint(
|
|
|
value: 135,
|
|
|
label: "135",
|
|
|
actualValue: '135',
|
|
|
displayTime: 'Mon',
|
|
|
unitOfMeasurement: 'mmHg',
|
|
|
time: DateTime.now().subtract(const Duration(days: 5)),
|
|
|
),
|
|
|
DataPoint(
|
|
|
value: 122,
|
|
|
label: "122",
|
|
|
actualValue: '122',
|
|
|
displayTime: 'Tue',
|
|
|
unitOfMeasurement: 'mmHg',
|
|
|
time: DateTime.now().subtract(const Duration(days: 4)),
|
|
|
),
|
|
|
DataPoint(
|
|
|
value: 140,
|
|
|
label: "140",
|
|
|
actualValue: '140',
|
|
|
displayTime: 'Wed',
|
|
|
unitOfMeasurement: 'mmHg',
|
|
|
time: DateTime.now().subtract(const Duration(days: 3)),
|
|
|
),
|
|
|
DataPoint(
|
|
|
value: 118,
|
|
|
label: "118",
|
|
|
actualValue: '118',
|
|
|
displayTime: 'Thu',
|
|
|
unitOfMeasurement: 'mmHg',
|
|
|
time: DateTime.now().subtract(const Duration(days: 2)),
|
|
|
),
|
|
|
DataPoint(
|
|
|
value: 125,
|
|
|
label: "125",
|
|
|
actualValue: '125',
|
|
|
displayTime: 'Fri',
|
|
|
unitOfMeasurement: 'mmHg',
|
|
|
time: DateTime.now().subtract(const Duration(days: 1)),
|
|
|
),
|
|
|
DataPoint(
|
|
|
value: 130,
|
|
|
label: "130",
|
|
|
actualValue: '130',
|
|
|
displayTime: 'Sat',
|
|
|
unitOfMeasurement: 'mmHg',
|
|
|
time: DateTime.now(),
|
|
|
),
|
|
|
];
|
|
|
|
|
|
return CustomBarChart(
|
|
|
dataPoints: data,
|
|
|
height: 300.h,
|
|
|
maxY: 150,
|
|
|
barColor: AppColors.bgGreenColor,
|
|
|
barWidth: 26.w,
|
|
|
barRadius: BorderRadius.circular(8),
|
|
|
bottomLabelColor: Colors.black,
|
|
|
bottomLabelSize: 12,
|
|
|
leftLabelInterval: .1,
|
|
|
leftLabelReservedSize: 40,
|
|
|
// Left axis label formatter (Y-axis)
|
|
|
leftLabelFormatter: (value) {
|
|
|
var labelValue = double.tryParse(value.toStringAsFixed(0));
|
|
|
|
|
|
if (labelValue == null) return SizedBox.shrink();
|
|
|
if (labelValue == 0 || labelValue == 150 / 2 || labelValue == 150) {
|
|
|
return Text(
|
|
|
labelValue.toStringAsFixed(0),
|
|
|
style: const TextStyle(
|
|
|
color: Colors.black26,
|
|
|
fontSize: 11,
|
|
|
),
|
|
|
);
|
|
|
}
|
|
|
|
|
|
return SizedBox.shrink();
|
|
|
},
|
|
|
|
|
|
// Bottom axis label formatter (X-axis - Days)
|
|
|
bottomLabelFormatter: (value, dataPoints) {
|
|
|
final index = value.toInt();
|
|
|
if (index >= 0 && index < dataPoints.length) {
|
|
|
return Text(
|
|
|
dataPoints[index].displayTime,
|
|
|
style: const TextStyle(
|
|
|
color: Colors.grey,
|
|
|
fontSize: 11,
|
|
|
),
|
|
|
);
|
|
|
}
|
|
|
return const Text('');
|
|
|
},
|
|
|
verticalInterval: 1/data.length,
|
|
|
getDrawingVerticalLine: (value) {
|
|
|
return FlLine(
|
|
|
color: AppColors.greyColor,
|
|
|
strokeWidth: 1,
|
|
|
);
|
|
|
},
|
|
|
showGridLines: true,
|
|
|
);
|
|
|
}
|
|
|
}
|