You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
SmartFit_Mobile/lib/View/home/home_view.dart

1072 lines
45 KiB

import 'package:dotted_dashed_line/dotted_dashed_line.dart';
import 'package:smartfit_app_mobile/common_widget/round_button.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:simple_animation_progress_bar/simple_animation_progress_bar.dart';
import 'package:simple_circular_progress_bar/simple_circular_progress_bar.dart';
import 'package:smartfit_app_mobile/view/home/activity_tracker.dart';
import 'package:smartfit_app_mobile/view/home/blank_view.dart';
import 'package:smartfit_app_mobile/view/home/notification_view.dart';
import '../../common/colo_extension.dart';
//import 'activity_tracker_view.dart';
//import 'finished_workout_view.dart';
//import 'notification_view.dart';
class HomeView extends StatefulWidget {
const HomeView({super.key});
@override
State<HomeView> createState() => _HomeViewState();
}
class _HomeViewState extends State<HomeView> {
List lastWorkoutArr = [
{
"name": "Full Body Workout",
"image": "assets/img/Workout1.png",
"kcal": "180",
"time": "20",
"progress": 0.3
},
{
"name": "Lower Body Workout",
"image": "assets/img/Workout2.png",
"kcal": "200",
"time": "30",
"progress": 0.4
},
{
"name": "Ab Workout",
"image": "assets/img/Workout3.png",
"kcal": "300",
"time": "40",
"progress": 0.7
},
];
List<int> showingTooltipOnSpots = [21];
List<FlSpot> allSpots = [FlSpot(0, 20)];
List waterArr = [
{"title": "6am - 8am", "subtitle": "600ml"},
{"title": "9am - 11am", "subtitle": "500ml"},
{"title": "11am - 2pm", "subtitle": "1000ml"},
{"title": "2pm - 4pm", "subtitle": "700ml"},
{"title": "4pm - now", "subtitle": "900ml"},
];
@override
Widget build(BuildContext context) {
var media = MediaQuery.of(context).size;
final lineBarsData = [
LineChartBarData(
showingIndicators: showingTooltipOnSpots,
spots: allSpots,
isCurved: false,
barWidth: 2,
belowBarData: BarAreaData(
show: true,
gradient: LinearGradient(colors: [
TColor.secondaryColor1.withOpacity(0.4),
TColor.secondaryColor2.withOpacity(0.1),
], begin: Alignment.topCenter, end: Alignment.bottomCenter),
),
dotData: FlDotData(show: false),
gradient: LinearGradient(
colors: TColor.secondaryG ,
),
),
];
final tooltipsOnBar = lineBarsData[0];
return Scaffold(
backgroundColor: TColor.white,
body: SingleChildScrollView(
child: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Bienvenue,",
style: TextStyle(color: TColor.gray, fontSize: 12),
),
Text(
"Benjelloun Othmane",
style: TextStyle(
color: TColor.black,
fontSize: 20,
fontWeight: FontWeight.w700),
),
],
),
IconButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const NotificationView(),
),
);
},
icon: Image.asset(
"assets/img/notification_active.png",
width: 25,
height: 25,
fit: BoxFit.fitHeight,
))
],
),
SizedBox(
height: media.width * 0.05,
),
Container(
height: media.width * 0.4,
decoration: BoxDecoration(
gradient: LinearGradient(colors: TColor.primaryG),
borderRadius: BorderRadius.circular(media.width * 0.075)),
child: Stack(alignment: Alignment.center, children: [
Image.asset(
"assets/img/bg_dots.png",
height: media.width * 0.4,
width: double.maxFinite,
fit: BoxFit.fitHeight,
),
Padding(
padding: const EdgeInsets.symmetric(
vertical: 25, horizontal: 25),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Graph 1",
style: TextStyle(
color: TColor.white,
fontSize: 14,
fontWeight: FontWeight.w700),
),
Text(
"Sous titre 1",
style: TextStyle(
color: TColor.white.withOpacity(0.7),
fontSize: 12),
),
SizedBox(
height: media.width * 0.05,
),
SizedBox(
width: 120,
height: 35,
child: RoundButton(
title: "Voir plus",
type: RoundButtonType.bgSGradient,
fontSize: 12,
fontWeight: FontWeight.w400,
onPressed: () {}))
],
),
AspectRatio(
aspectRatio: 1,
child: PieChart(
PieChartData(
pieTouchData: PieTouchData(
touchCallback:
(FlTouchEvent event, pieTouchResponse) {},
),
startDegreeOffset: 250,
borderData: FlBorderData(
show: false,
),
sectionsSpace: 1,
centerSpaceRadius: 0,
sections: showingSections(),
),
),
),
],
),
)
]),
),
SizedBox(
height: media.width * 0.05,
),
Container(
padding:
const EdgeInsets.symmetric(vertical: 15, horizontal: 15),
decoration: BoxDecoration(
color: TColor.primaryColor2.withOpacity(0.3),
borderRadius: BorderRadius.circular(15),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Suivi d'activité",
style: TextStyle(
color: TColor.black,
fontSize: 14,
fontWeight: FontWeight.w700),
),
SizedBox(
width: 70,
height: 25,
child: RoundButton(
title: "Voir",
type: RoundButtonType.bgGradient,
fontSize: 12,
fontWeight: FontWeight.w400,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const ActivityTrackerView(),
),
);
},
),
)
],
),
),
SizedBox(
height: media.width * 0.05,
),
Text(
"Status d'activité",
style: TextStyle(
color: TColor.black,
fontSize: 16,
fontWeight: FontWeight.w700),
),
SizedBox(
height: media.width * 0.02,
),
ClipRRect(
borderRadius: BorderRadius.circular(25),
child: Container(
height: media.width * 0.4,
width: double.maxFinite,
decoration: BoxDecoration(
color: TColor.primaryColor2.withOpacity(0.3),
borderRadius: BorderRadius.circular(25),
),
child: Stack(
alignment: Alignment.topLeft,
children: [
Padding(
padding: const EdgeInsets.symmetric(
vertical: 20, horizontal: 20),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Graph 2 ( rhythme cardiaque )",
style: TextStyle(
color: TColor.black,
fontSize: 16,
fontWeight: FontWeight.w700),
),
ShaderMask(
blendMode: BlendMode.srcIn,
shaderCallback: (bounds) {
return LinearGradient(
colors: TColor.primaryG,
begin: Alignment.centerLeft,
end: Alignment.centerRight)
.createShader(Rect.fromLTRB(
0, 0, bounds.width, bounds.height));
},
child: Text(
"78 BPM",
style: TextStyle(
color: TColor.primaryColor1.withOpacity(0.7),
fontWeight: FontWeight.w700,
fontSize: 18),
),
),
],
),
),
LineChart(
LineChartData(
showingTooltipIndicators:
showingTooltipOnSpots.map((index) {
return ShowingTooltipIndicators([
LineBarSpot(
tooltipsOnBar,
lineBarsData.indexOf(tooltipsOnBar),
tooltipsOnBar.spots[index],
),
]);
}).toList(),
lineTouchData: LineTouchData(
enabled: true,
handleBuiltInTouches: false,
touchCallback: (FlTouchEvent event,
LineTouchResponse? response) {
if (response == null ||
response.lineBarSpots == null) {
return;
}
if (event is FlTapUpEvent) {
final spotIndex =
response.lineBarSpots!.first.spotIndex;
showingTooltipOnSpots.clear();
setState(() {
showingTooltipOnSpots.add(spotIndex);
});
}
},
mouseCursorResolver: (FlTouchEvent event,
LineTouchResponse? response) {
if (response == null ||
response.lineBarSpots == null) {
return SystemMouseCursors.basic;
}
return SystemMouseCursors.click;
},
getTouchedSpotIndicator:
(LineChartBarData barData,
List<int> spotIndexes) {
return spotIndexes.map((index) {
return TouchedSpotIndicatorData(
FlLine(
color: TColor.secondaryColor1,
),
FlDotData(
show: true,
getDotPainter:
(spot, percent, barData, index) =>
FlDotCirclePainter(
radius: 3,
color: Colors.white,
strokeWidth: 3,
strokeColor: TColor.secondaryColor1,
),
),
);
}).toList();
},
touchTooltipData: LineTouchTooltipData(
tooltipBgColor: TColor.secondaryColor1,
tooltipRoundedRadius: 20,
getTooltipItems:
(List<LineBarSpot> lineBarsSpot) {
return lineBarsSpot.map((lineBarSpot) {
return LineTooltipItem(
"il y a ${lineBarSpot.x.toInt()} minutes",
const TextStyle(
color: Colors.white,
fontSize: 10,
fontWeight: FontWeight.bold,
),
);
}).toList();
},
),
),
lineBarsData: lineBarsData,
minY: 0,
maxY: 130,
titlesData: FlTitlesData(
show: false,
),
gridData: FlGridData(show: false),
borderData: FlBorderData(
show: true,
border: Border.all(
color: Colors.transparent,
),
),
),
)
],
),
),
),
SizedBox(
height: media.width * 0.05,
),
Row(
children: [
Expanded(
child: Container(
height: media.width * 0.95,
padding: const EdgeInsets.symmetric(
vertical: 25, horizontal: 20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(25),
boxShadow: const [
BoxShadow(color: Colors.black12, blurRadius: 2)
]),
child: Row(
children: [
SimpleAnimationProgressBar(
height: media.width * 0.85,
width: media.width * 0.07,
backgroundColor: Colors.grey.shade100,
foregrondColor: Colors.purple,
ratio: 0.5,
direction: Axis.vertical,
curve: Curves.fastLinearToSlowEaseIn,
duration: const Duration(seconds: 3),
borderRadius: BorderRadius.circular(15),
gradientColor: LinearGradient(
colors: TColor.primaryG,
begin: Alignment.bottomCenter,
end: Alignment.topCenter),
),
const SizedBox(
width: 10,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Graph 3",
style: TextStyle(
color: TColor.black,
fontSize: 12,
fontWeight: FontWeight.w700),
),
ShaderMask(
blendMode: BlendMode.srcIn,
shaderCallback: (bounds) {
return LinearGradient(
colors: TColor.primaryG,
begin: Alignment.centerLeft,
end: Alignment.centerRight)
.createShader(Rect.fromLTRB(
0, 0, bounds.width, bounds.height));
},
child: Text(
"ex : objectif",
style: TextStyle(
color: TColor.white.withOpacity(0.7),
fontWeight: FontWeight.w700,
fontSize: 14),
),
),
const SizedBox(
height: 10,
),
Text(
"Mis à jour en temps réel",
style: TextStyle(
color: TColor.gray,
fontSize: 12,
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: waterArr.map((wObj) {
var isLast = wObj == waterArr.last;
return Row(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Column(
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Container(
margin:
const EdgeInsets.symmetric(
vertical: 4),
width: 10,
height: 10,
decoration: BoxDecoration(
color: TColor.secondaryColor1
.withOpacity(0.5),
borderRadius:
BorderRadius.circular(5),
),
),
if (!isLast)
DottedDashedLine(
height: media.width * 0.078,
width: 0,
dashColor: TColor
.secondaryColor1
.withOpacity(0.5),
axis: Axis.vertical)
],
),
const SizedBox(
width: 10,
),
Column(
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
wObj["title"].toString(),
style: TextStyle(
color: TColor.gray,
fontSize: 10,
),
),
ShaderMask(
blendMode: BlendMode.srcIn,
shaderCallback: (bounds) {
return LinearGradient(
colors:
TColor.secondaryG,
begin: Alignment
.centerLeft,
end: Alignment
.centerRight)
.createShader(Rect.fromLTRB(
0,
0,
bounds.width,
bounds.height));
},
child: Text(
wObj["subtitle"].toString(),
style: TextStyle(
color: TColor.white
.withOpacity(0.7),
fontSize: 12),
),
),
],
)
],
);
}).toList(),
)
],
))
],
),
),
),
SizedBox(
width: media.width * 0.05,
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: double.maxFinite,
height: media.width * 0.45,
padding: const EdgeInsets.symmetric(
vertical: 25, horizontal: 20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(25),
boxShadow: const [
BoxShadow(color: Colors.black12, blurRadius: 2)
]),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Graph 4",
style: TextStyle(
color: TColor.black,
fontSize: 12,
fontWeight: FontWeight.w700),
),
ShaderMask(
blendMode: BlendMode.srcIn,
shaderCallback: (bounds) {
return LinearGradient(
colors: TColor.primaryG,
begin: Alignment.centerLeft,
end: Alignment.centerRight)
.createShader(Rect.fromLTRB(
0, 0, bounds.width, bounds.height));
},
child: Text(
"durée",
style: TextStyle(
color: TColor.white.withOpacity(0.7),
fontWeight: FontWeight.w700,
fontSize: 14),
),
),
const Spacer(),
Image.asset("assets/img/sleep_graph.png",
width: double.maxFinite,
height: 80,
fit: BoxFit.fitWidth)
]),
),
SizedBox(
height: media.width * 0.05,
),
Container(
width: double.maxFinite,
height: media.width * 0.45,
padding: const EdgeInsets.symmetric(
vertical: 25, horizontal: 20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(25),
boxShadow: const [
BoxShadow(color: Colors.black12, blurRadius: 2)
]),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Calories",
style: TextStyle(
color: TColor.black,
fontSize: 12,
fontWeight: FontWeight.w700),
),
ShaderMask(
blendMode: BlendMode.srcIn,
shaderCallback: (bounds) {
return LinearGradient(
colors: TColor.primaryG,
begin: Alignment.centerLeft,
end: Alignment.centerRight)
.createShader(Rect.fromLTRB(
0, 0, bounds.width, bounds.height));
},
child: Text(
"760 kCal",
style: TextStyle(
color: TColor.white.withOpacity(0.7),
fontWeight: FontWeight.w700,
fontSize: 14),
),
),
const Spacer(),
Container(
alignment: Alignment.center,
child: SizedBox(
width: media.width * 0.2,
height: media.width * 0.2,
child: Stack(
alignment: Alignment.center,
children: [
Container(
width: media.width * 0.15,
height: media.width * 0.15,
alignment: Alignment.center,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: TColor.primaryG),
borderRadius: BorderRadius.circular(
media.width * 0.075),
),
child: FittedBox(
child: Text(
"230kCal\nrestantes",
textAlign: TextAlign.center,
style: TextStyle(
color: TColor.white,
fontSize: 11),
),
),
),
SimpleCircularProgressBar(
progressStrokeWidth: 10,
backStrokeWidth: 10,
progressColors: TColor.primaryG,
backColor: Colors.grey.shade100,
valueNotifier: ValueNotifier(50),
startAngle: -180,
),
],
),
),
)
]),
),
],
))
],
),
SizedBox(
height: media.width * 0.1,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"graph 5",
style: TextStyle(
color: TColor.black,
fontSize: 16,
fontWeight: FontWeight.w700),
),
Container(
height: 30,
padding: const EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(
gradient: LinearGradient(colors: TColor.primaryG),
borderRadius: BorderRadius.circular(15),
),
child: DropdownButtonHideUnderline(
child: DropdownButton(
items: ["Semaine", "Mois"]
.map((name) => DropdownMenuItem(
value: name,
child: Text(
name,
style: TextStyle(
color: TColor.gray, fontSize: 14),
),
))
.toList(),
onChanged: (value) {},
icon: Icon(Icons.expand_more, color: TColor.white),
hint: Text(
"Semaine",
textAlign: TextAlign.center,
style:
TextStyle(color: TColor.white, fontSize: 12),
),
),
)),
],
),
SizedBox(
height: media.width * 0.05,
),
Container(
padding: const EdgeInsets.only(left: 15),
height: media.width * 0.5,
width: double.maxFinite,
child: LineChart(
LineChartData(
showingTooltipIndicators:
showingTooltipOnSpots.map((index) {
return ShowingTooltipIndicators([
LineBarSpot(
tooltipsOnBar,
lineBarsData.indexOf(tooltipsOnBar),
tooltipsOnBar.spots[index],
),
]);
}).toList(),
lineTouchData: LineTouchData(
enabled: true,
handleBuiltInTouches: false,
touchCallback: (FlTouchEvent event,
LineTouchResponse? response) {
if (response == null ||
response.lineBarSpots == null) {
return;
}
if (event is FlTapUpEvent) {
final spotIndex =
response.lineBarSpots!.first.spotIndex;
showingTooltipOnSpots.clear();
setState(() {
showingTooltipOnSpots.add(spotIndex);
});
}
},
mouseCursorResolver: (FlTouchEvent event,
LineTouchResponse? response) {
if (response == null ||
response.lineBarSpots == null) {
return SystemMouseCursors.basic;
}
return SystemMouseCursors.click;
},
getTouchedSpotIndicator: (LineChartBarData barData,
List<int> spotIndexes) {
return spotIndexes.map((index) {
return TouchedSpotIndicatorData(
FlLine(
color: Colors.transparent,
),
FlDotData(
show: true,
getDotPainter:
(spot, percent, barData, index) =>
FlDotCirclePainter(
radius: 3,
color: Colors.white,
strokeWidth: 3,
strokeColor: TColor.secondaryColor1,
),
),
);
}).toList();
},
touchTooltipData: LineTouchTooltipData(
tooltipBgColor: TColor.secondaryColor1,
tooltipRoundedRadius: 20,
getTooltipItems: (List<LineBarSpot> lineBarsSpot) {
return lineBarsSpot.map((lineBarSpot) {
return LineTooltipItem(
"il y a ${lineBarSpot.x.toInt()} minutes",
const TextStyle(
color: Colors.white,
fontSize: 10,
fontWeight: FontWeight.bold,
),
);
}).toList();
},
),
),
lineBarsData: lineBarsData1,
minY: -0.5,
maxY: 110,
titlesData: FlTitlesData(
show: true,
leftTitles: AxisTitles(),
topTitles: AxisTitles(),
bottomTitles: AxisTitles(
sideTitles: bottomTitles,
),
rightTitles: AxisTitles(
sideTitles: rightTitles,
)),
gridData: FlGridData(
show: true,
drawHorizontalLine: true,
horizontalInterval: 25,
drawVerticalLine: false,
getDrawingHorizontalLine: (value) {
return FlLine(
color: TColor.gray.withOpacity(0.15),
strokeWidth: 2,
);
},
),
borderData: FlBorderData(
show: true,
border: Border.all(
color: Colors.transparent,
),
),
),
)),
SizedBox(
height: media.width * 0.05,
),
SizedBox(
height: media.width * 0.1,
),
],
),
),
),
),
);
}
void updateChartData(List<FlSpot> newData) {
setState(() {
allSpots = newData;
});
}
List<PieChartSectionData> showingSections() {
return List.generate(
2,
(i) {
var color0 = TColor.secondaryColor1;
switch (i) {
case 0:
return PieChartSectionData(
color: color0,
value: 33,
title: '',
radius: 55,
titlePositionPercentageOffset: 0.55,
badgeWidget: const Text(
"20,1",
style: TextStyle(
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.w700),
));
case 1:
return PieChartSectionData(
color: Colors.white,
value: 75,
title: '',
radius: 45,
titlePositionPercentageOffset: 0.55,
);
default:
throw Error();
}
},
);
}
LineTouchData get lineTouchData1 => LineTouchData(
handleBuiltInTouches: true,
touchTooltipData: LineTouchTooltipData(
tooltipBgColor: Colors.blueGrey.withOpacity(0.8),
),
);
List<LineChartBarData> get lineBarsData1 => [
lineChartBarData1_1,
lineChartBarData1_2,
];
LineChartBarData get lineChartBarData1_1 => LineChartBarData(
isCurved: true,
gradient: LinearGradient(colors: [
TColor.primaryColor2.withOpacity(0.5),
TColor.primaryColor1.withOpacity(0.5),
]),
barWidth: 4,
isStrokeCapRound: true,
dotData: FlDotData(show: false),
belowBarData: BarAreaData(show: false),
spots: const [
FlSpot(1, 35),
FlSpot(2, 70),
FlSpot(3, 40),
FlSpot(4, 80),
FlSpot(5, 25),
FlSpot(6, 70),
FlSpot(7, 35),
],
);
LineChartBarData get lineChartBarData1_2 => LineChartBarData(
isCurved: true,
gradient: LinearGradient(colors: [
TColor.secondaryColor2.withOpacity(0.5),
TColor.secondaryColor1.withOpacity(0.5),
]),
barWidth: 2,
isStrokeCapRound: true,
dotData: FlDotData(show: false),
belowBarData: BarAreaData(
show: false,
),
spots: const [
FlSpot(1, 80),
FlSpot(2, 50),
FlSpot(3, 90),
FlSpot(4, 40),
FlSpot(5, 80),
FlSpot(6, 35),
FlSpot(7, 60),
],
);
SideTitles get rightTitles => SideTitles(
getTitlesWidget: rightTitleWidgets,
showTitles: true,
interval: 20,
reservedSize: 40,
);
Widget rightTitleWidgets(double value, TitleMeta meta) {
String text;
switch (value.toInt()) {
case 0:
text = '0%';
break;
case 20:
text = '20%';
break;
case 40:
text = '40%';
break;
case 60:
text = '60%';
break;
case 80:
text = '80%';
break;
case 100:
text = '100%';
break;
default:
return Container();
}
return Text(text,
style: TextStyle(
color: TColor.gray,
fontSize: 12,
),
textAlign: TextAlign.center);
}
SideTitles get bottomTitles => SideTitles(
showTitles: true,
reservedSize: 32,
interval: 1,
getTitlesWidget: bottomTitleWidgets,
);
Widget bottomTitleWidgets(double value, TitleMeta meta) {
var style = TextStyle(
color: TColor.gray,
fontSize: 12,
);
Widget text;
switch (value.toInt()) {
case 1:
text = Text('Dim', style: style);
break;
case 2:
text = Text('Lun', style: style);
break;
case 3:
text = Text('Mar', style: style);
break;
case 4:
text = Text('Mer', style: style);
break;
case 5:
text = Text('Jeu', style: style);
break;
case 6:
text = Text('Ven', style: style);
break;
case 7:
text = Text('Sam', style: style);
break;
default:
text = Text('', style: style);
break;
}
return SideTitleWidget(
axisSide: meta.axisSide,
space: 10,
child: text,
);
}
}