@@ -5,6 +5,7 @@ import 'package:fl_chart/fl_chart.dart';
55import 'package:hack_space_temp/Screens/components/bottom_nav_bar.dart' ;
66// import 'package:hack_space_temp/Screens/components/my_button.dart';
77import 'package:intl/intl.dart' ;
8+ import 'package:google_generative_ai/google_generative_ai.dart' ;
89
910class UserProfilePage extends StatefulWidget {
1011 final String userName;
@@ -21,6 +22,46 @@ class UserProfilePage extends StatefulWidget {
2122 @override
2223 State <UserProfilePage > createState () => _UserProfilePageState ();
2324}
25+ String advice = '' ;
26+ Future <String > generateAdvice ({
27+ required double todayDist,
28+ required int todayTime,
29+ required Map <String , dynamic > weekAc,
30+ required int height,
31+ required int weight,
32+ }) async {
33+ String userDataSummary = '''
34+ Today, you ran a distance of $todayDist meters in $todayTime seconds.
35+ Your weekly activity summary is: ${weekAc .map ((key , value ) => MapEntry (key , '${value .toString ()} meters' ))}.
36+ Your height is ${height .toStringAsFixed (2 )} meters and your weight is ${weight .toStringAsFixed (2 )} kilograms.
37+ ''' ;
38+
39+ final model = GenerativeModel (
40+ model: 'gemini-1.5-pro' ,
41+ apiKey: 'AIzaSyACou9Lb1KnQ4GHZtK-ci4_WGZNlfgD2pE' ,
42+ );
43+
44+ final prompt = '''
45+ Based on the following user data, provide personalized health and fitness advice:
46+
47+ $userDataSummary
48+
49+ Please include recommendations for improving fitness, diet tips, and any suggestions for running efficiency.
50+ ''' ;
51+
52+ try {
53+ final result = await model.generateContent ([Content .text (prompt)]);
54+ return result.text ?? 'No advice generated.' ;
55+ } catch (e) {
56+ print ('Error generating content: $e ' );
57+ return 'Failed to generate advice. Please try again later.' ;
58+ }
59+ }
60+
61+
62+ // void main() async {
63+ // await generateAdvice();
64+ // }
2465
2566List <FriendData > friendLeaderboard = [];
2667
@@ -35,6 +76,8 @@ class _UserProfilePageState extends State<UserProfilePage> {
3576 List <RunningData > runningData = [];
3677 bool isLoading = true ;
3778 String errorMessage = '' ;
79+ String aiAdvice = '' ;
80+ bool isGeneratingAdvice = false ;
3881
3982 @override
4083 void initState () {
@@ -432,76 +475,151 @@ class _UserProfilePageState extends State<UserProfilePage> {
432475 }
433476
434477 Widget _buildLeaderboard () {
435- // Create a combined leaderboard list with the user and friends
436- List <FriendData > fullLeaderboard = [
437- FriendData (username: userName, todayDist: today_dist, todayTime: today_time)
438- ]..addAll (friendLeaderboard);
439-
440- // Sort the leaderboard based on distance
441- fullLeaderboard.sort ((a, b) => b.todayDist.compareTo (a.todayDist));
442-
443- return Container (
444- decoration: BoxDecoration (
445- color: Colors .white, // Background color for the leaderboard
446- borderRadius: BorderRadius .circular (12 ), // Rounded corners
447- boxShadow: [
448- BoxShadow (
449- color: Colors .grey.withOpacity (0.5 ), // Shadow color
450- spreadRadius: 2 , // Spread radius
451- blurRadius: 5 , // Blur radius
452- offset: const Offset (0 , 3 ), // Shadow offset
478+ // Create a combined leaderboard list with the user and friends
479+ List <FriendData > fullLeaderboard = [
480+ FriendData (username: userName, todayDist: today_dist, todayTime: today_time)
481+ ]..addAll (friendLeaderboard);
482+
483+ // Sort the leaderboard based on distance
484+ fullLeaderboard.sort ((a, b) => b.todayDist.compareTo (a.todayDist));
485+
486+ return Container (
487+ decoration: BoxDecoration (
488+ color: Colors .white, // Background color for the leaderboard
489+ borderRadius: BorderRadius .circular (12 ), // Rounded corners
490+ boxShadow: [
491+ BoxShadow (
492+ color: Colors .grey.withOpacity (0.5 ), // Shadow color
493+ spreadRadius: 2 , // Spread radius
494+ blurRadius: 5 , // Blur radius
495+ offset: const Offset (0 , 3 ), // Shadow offset
496+ ),
497+ ],
498+ ),
499+ padding: const EdgeInsets .all (16 ), // Padding for the container
500+ child: Column (
501+ crossAxisAlignment: CrossAxisAlignment .start,
502+ children: [
503+ const Text (
504+ 'Leaderboard' ,
505+ style: TextStyle (
506+ fontSize: 24 ,
507+ fontWeight: FontWeight .bold,
508+ color: Colors .black,
453509 ),
454- ],
455- ),
456- padding: const EdgeInsets .all (16 ), // Padding for the container
457- child: Column (
458- crossAxisAlignment: CrossAxisAlignment .start,
459- children: [
460- const Text (
461- 'Leaderboard' ,
462- style: TextStyle (
463- fontSize: 24 ,
464- fontWeight: FontWeight .bold,
465- color: Colors .black,
510+ ),
511+ const SizedBox (height: 10 ),
512+ fullLeaderboard.isEmpty
513+ ? const Text (
514+ "No data to show." ,
515+ style: TextStyle (color: Colors .grey),
516+ )
517+ : ListView .builder (
518+ shrinkWrap: true ,
519+ physics: const NeverScrollableScrollPhysics (),
520+ itemCount: fullLeaderboard.length,
521+ itemBuilder: (context, index) {
522+ final participant = fullLeaderboard[index];
523+ return ListTile (
524+ leading: Text (
525+ '#${index + 1 }' ,
526+ style: const TextStyle (fontWeight: FontWeight .bold),
527+ ),
528+ title: Text (
529+ participant.username == userName
530+ ? 'You'
531+ : participant.username,
532+ ),
533+ subtitle: Text (
534+ 'Distance: ${formatDistance (participant .todayDist )}, Time: ${formatTime (participant .todayTime )}' ,
535+ ),
536+ tileColor: participant.username == userName
537+ ? Colors .yellow.withOpacity (0.2 ) // Highlight the user
538+ : null ,
539+ );
540+ },
541+ ),
542+ const SizedBox (height: 20 ),
543+ Center (
544+ child: TextButton (
545+ onPressed: isGeneratingAdvice ? null : () async {
546+ setState (() {
547+ isGeneratingAdvice = true ;
548+ });
549+ try {
550+ DocumentSnapshot userDoc =
551+ await FirebaseFirestore .instance.collection ('users' ).doc (uid).get ();
552+ Map <String , dynamic > data = userDoc.data () as Map <String , dynamic >;
553+ String generatedAdvice = await generateAdvice (
554+ todayDist: today_dist,
555+ todayTime: today_time,
556+ weekAc: data['week_ac' ],
557+ height: data['height' ],
558+ weight: data['weight' ],
559+ );
560+ setState (() {
561+ aiAdvice = generatedAdvice;
562+ isGeneratingAdvice = false ;
563+ });
564+ } catch (e) {
565+ print ('Error generating advice: $e ' );
566+ setState (() {
567+ aiAdvice = 'Failed to generate advice. Please try again later.' ;
568+ isGeneratingAdvice = false ;
569+ });
570+ }
571+ },
572+ style: TextButton .styleFrom (
573+ backgroundColor: const Color (0xFF229DAB ),
574+ padding: const EdgeInsets .symmetric (horizontal: 20 , vertical: 10 ),
575+ ),
576+ child: isGeneratingAdvice
577+ ? const CircularProgressIndicator (color: Colors .white)
578+ : const Text (
579+ 'AI Coach' ,
580+ style: TextStyle (
581+ color: Colors .white,
582+ fontSize: 18 ,
583+ fontWeight: FontWeight .bold,
584+ ),
585+ ),
466586 ),
467587 ),
468- const SizedBox (height: 10 ),
469- fullLeaderboard.isEmpty
470- ? const Text (
471- "No data to show." ,
472- style: TextStyle (color: Colors .grey),
473- )
474- : ListView .builder (
475- shrinkWrap: true ,
476- physics: const NeverScrollableScrollPhysics (),
477- itemCount: fullLeaderboard.length,
478- itemBuilder: (context, index) {
479- final participant = fullLeaderboard[index];
480- return ListTile (
481- leading: Text (
482- '#${index + 1 }' ,
483- style: const TextStyle (fontWeight: FontWeight .bold),
484- ),
485- title: Text (
486- participant.username == userName
487- ? 'You'
488- : participant.username,
489- ),
490- subtitle: Text (
491- 'Distance: ${formatDistance (participant .todayDist )}, Time: ${formatTime (participant .todayTime )}' ,
492- ),
493- tileColor: participant.username == userName
494- ? Colors .yellow.withOpacity (0.2 ) // Highlight the user
495- : null ,
496- );
497- },
498- ),
588+ if (aiAdvice.isNotEmpty) ...[
589+ const SizedBox (height: 20 ),
590+ Container (
591+ padding: const EdgeInsets .all (16 ),
592+ decoration: BoxDecoration (
593+ color: Colors .grey[200 ],
594+ borderRadius: BorderRadius .circular (8 ),
595+ ),
596+ child: Column (
597+ crossAxisAlignment: CrossAxisAlignment .start,
598+ children: [
599+ const Text (
600+ 'AI Coach Advice:' ,
601+ style: TextStyle (
602+ fontWeight: FontWeight .bold,
603+ fontSize: 18 ,
604+ ),
605+ ),
606+ const SizedBox (height: 8 ),
607+ Text (
608+ aiAdvice,
609+ style: const TextStyle (fontSize: 16 ),
610+ ),
611+ ],
612+ ),
613+ ),
614+ ],
499615 ],
500616 ),
501617 );
502618 }
503619
504620
621+
622+
505623}
506624
507625class FriendData {
@@ -527,4 +645,4 @@ class RunningData {
527645
528646 @override
529647 String toString () => 'RunningData(date: $date , distance: $distance )' ;
530- }
648+ }
0 commit comments