After Width: | Height: | Size: 684 B |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 714 B |
After Width: | Height: | Size: 932 B |
After Width: | Height: | Size: 798 B |
After Width: | Height: | Size: 722 B |
After Width: | Height: | Size: 358 B |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 8.5 KiB |
After Width: | Height: | Size: 599 B |
After Width: | Height: | Size: 637 B |
After Width: | Height: | Size: 760 B |
After Width: | Height: | Size: 830 B |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 423 B |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 572 B |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 22 KiB |
@ -1 +1,2 @@
|
||||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
|
@ -1 +1,2 @@
|
||||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
|
@ -0,0 +1,44 @@
|
||||
# Uncomment this line to define a global platform for your project
|
||||
# platform :ios, '11.0'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
||||
project 'Runner', {
|
||||
'Debug' => :debug,
|
||||
'Profile' => :release,
|
||||
'Release' => :release,
|
||||
}
|
||||
|
||||
def flutter_root
|
||||
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
|
||||
unless File.exist?(generated_xcode_build_settings_path)
|
||||
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
|
||||
end
|
||||
|
||||
File.foreach(generated_xcode_build_settings_path) do |line|
|
||||
matches = line.match(/FLUTTER_ROOT\=(.*)/)
|
||||
return matches[1].strip if matches
|
||||
end
|
||||
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
|
||||
end
|
||||
|
||||
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
|
||||
|
||||
flutter_ios_podfile_setup
|
||||
|
||||
target 'Runner' do
|
||||
use_frameworks!
|
||||
use_modular_headers!
|
||||
|
||||
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
|
||||
target 'RunnerTests' do
|
||||
inherit! :search_paths
|
||||
end
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
flutter_additional_ios_build_settings(target)
|
||||
end
|
||||
end
|
@ -0,0 +1,28 @@
|
||||
import 'package:smartfit_app_mobile/common_widget/steps.dart';
|
||||
import 'package:smartfit_app_mobile/common_widget/dates.dart';
|
||||
import 'package:smartfit_app_mobile/common_widget/graph.dart';
|
||||
import 'package:smartfit_app_mobile/common_widget/info.dart' hide Stats;
|
||||
import 'package:smartfit_app_mobile/common_widget/stats.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class Activity extends StatelessWidget {
|
||||
const Activity({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
body: Column(
|
||||
children: const [
|
||||
Divider(height: 80),
|
||||
Steps(),
|
||||
Graph(),
|
||||
Info(),
|
||||
Divider(height: 30),
|
||||
Stats(),
|
||||
SizedBox(height: 30),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,431 @@
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../common/colo_extension.dart';
|
||||
import '../../common_widget/latest_activity_row.dart';
|
||||
import '../../common_widget/today_target_cell.dart';
|
||||
|
||||
class ActivityTrackerView extends StatefulWidget {
|
||||
const ActivityTrackerView({super.key});
|
||||
|
||||
@override
|
||||
State<ActivityTrackerView> createState() => _ActivityTrackerViewState();
|
||||
}
|
||||
|
||||
class _ActivityTrackerViewState extends State<ActivityTrackerView> {
|
||||
int touchedIndex = -1;
|
||||
|
||||
List latestArr = [
|
||||
{
|
||||
"image": "assets/img/workout1.svg",
|
||||
"title": "Drinking 300ml Water",
|
||||
"time": "About 1 minutes ago"
|
||||
},
|
||||
{
|
||||
"image": "assets/img/workout1.svg",
|
||||
"title": "Eat Snack (Fitbar)",
|
||||
"time": "About 3 hours ago"
|
||||
},
|
||||
];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var media = MediaQuery.of(context).size;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: TColor.white,
|
||||
centerTitle: true,
|
||||
elevation: 0,
|
||||
leading: InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Container(
|
||||
margin: const EdgeInsets.all(8),
|
||||
height: 40,
|
||||
width: 40,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: TColor.lightGray,
|
||||
borderRadius: BorderRadius.circular(10)),
|
||||
child: Image.asset(
|
||||
"assets/img/black_btn.png",
|
||||
width: 15,
|
||||
height: 15,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
),
|
||||
title: Text(
|
||||
"Suivi d'activité",
|
||||
style: TextStyle(
|
||||
color: TColor.black, fontSize: 16, fontWeight: FontWeight.w700),
|
||||
),
|
||||
actions: [
|
||||
InkWell(
|
||||
onTap: () {},
|
||||
child: Container(
|
||||
margin: const EdgeInsets.all(8),
|
||||
height: 40,
|
||||
width: 40,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: TColor.lightGray,
|
||||
borderRadius: BorderRadius.circular(10)),
|
||||
child: Image.asset(
|
||||
"assets/img/more_btn.png",
|
||||
width: 15,
|
||||
height: 15,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
backgroundColor: TColor.white,
|
||||
body: SingleChildScrollView(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 25, horizontal: 25),
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 15, horizontal: 15),
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(colors: [
|
||||
TColor.primaryColor2.withOpacity(0.3),
|
||||
TColor.primaryColor1.withOpacity(0.3)
|
||||
]),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Objectif d'aujourd'hui",
|
||||
style: TextStyle(
|
||||
color: TColor.black,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w700),
|
||||
),
|
||||
SizedBox(
|
||||
width: 30,
|
||||
height: 30,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: TColor.primaryG,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: MaterialButton(
|
||||
onPressed: () {},
|
||||
padding: EdgeInsets.zero,
|
||||
height: 30,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(25)),
|
||||
textColor: TColor.primaryColor1,
|
||||
minWidth: double.maxFinite,
|
||||
elevation: 0,
|
||||
color: Colors.transparent,
|
||||
child: const Icon(
|
||||
Icons.add,
|
||||
color: Colors.white,
|
||||
size: 15,
|
||||
)),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
const Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TodayTargetCell(
|
||||
icon: "assets/img/workout1.svg",
|
||||
value: "800",
|
||||
title: "Calories",
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 15,
|
||||
),
|
||||
Expanded(
|
||||
child: TodayTargetCell(
|
||||
icon: "assets/img/workout1.svg",
|
||||
value: "2400",
|
||||
title: "Nombre pas",
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: media.width * 0.1,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Activité journalière",
|
||||
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(
|
||||
height: media.width * 0.5,
|
||||
padding: const EdgeInsets.symmetric(vertical: 15 , horizontal: 0),
|
||||
decoration: BoxDecoration(
|
||||
color: TColor.white,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
boxShadow: const [
|
||||
BoxShadow(color: Colors.black12, blurRadius: 3)
|
||||
]),
|
||||
child: BarChart(
|
||||
|
||||
BarChartData(
|
||||
barTouchData: BarTouchData(
|
||||
touchTooltipData: BarTouchTooltipData(
|
||||
tooltipBgColor: Colors.grey,
|
||||
tooltipHorizontalAlignment: FLHorizontalAlignment.right,
|
||||
tooltipMargin: 10,
|
||||
getTooltipItem: (group, groupIndex, rod, rodIndex) {
|
||||
String weekDay;
|
||||
switch (group.x) {
|
||||
case 0:
|
||||
weekDay = 'Monday';
|
||||
break;
|
||||
case 1:
|
||||
weekDay = 'Tuesday';
|
||||
break;
|
||||
case 2:
|
||||
weekDay = 'Wednesday';
|
||||
break;
|
||||
case 3:
|
||||
weekDay = 'Thursday';
|
||||
break;
|
||||
case 4:
|
||||
weekDay = 'Friday';
|
||||
break;
|
||||
case 5:
|
||||
weekDay = 'Saturday';
|
||||
break;
|
||||
case 6:
|
||||
weekDay = 'Sunday';
|
||||
break;
|
||||
default:
|
||||
throw Error();
|
||||
}
|
||||
return BarTooltipItem(
|
||||
'$weekDay\n',
|
||||
const TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14,
|
||||
),
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: (rod.toY - 1).toString(),
|
||||
style: TextStyle(
|
||||
color: TColor.white,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
touchCallback: (FlTouchEvent event, barTouchResponse) {
|
||||
setState(() {
|
||||
if (!event.isInterestedForInteractions ||
|
||||
barTouchResponse == null ||
|
||||
barTouchResponse.spot == null) {
|
||||
touchedIndex = -1;
|
||||
return;
|
||||
}
|
||||
touchedIndex =
|
||||
barTouchResponse.spot!.touchedBarGroupIndex;
|
||||
});
|
||||
},
|
||||
),
|
||||
titlesData: FlTitlesData(
|
||||
show: true,
|
||||
rightTitles: AxisTitles(
|
||||
sideTitles: SideTitles(showTitles: false),
|
||||
),
|
||||
topTitles: AxisTitles(
|
||||
sideTitles: SideTitles(showTitles: false),
|
||||
),
|
||||
bottomTitles: AxisTitles(
|
||||
sideTitles: SideTitles(
|
||||
showTitles: true,
|
||||
getTitlesWidget: getTitles,
|
||||
reservedSize: 38,
|
||||
),
|
||||
),
|
||||
leftTitles: AxisTitles(
|
||||
sideTitles: SideTitles(
|
||||
showTitles: false,
|
||||
),
|
||||
),
|
||||
),
|
||||
borderData: FlBorderData(
|
||||
show: false,
|
||||
),
|
||||
barGroups: showingGroups(),
|
||||
gridData: FlGridData(show: false),
|
||||
)
|
||||
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
height: media.width * 0.05,
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
height: media.width * 0.1,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget getTitles(double value, TitleMeta meta) {
|
||||
var style = TextStyle(
|
||||
color: TColor.gray,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 12,
|
||||
);
|
||||
Widget text;
|
||||
switch (value.toInt()) {
|
||||
case 0:
|
||||
text = Text('Dim', style: style);
|
||||
break;
|
||||
case 1:
|
||||
text = Text('Lun', style: style);
|
||||
break;
|
||||
case 2:
|
||||
text = Text('Mar', style: style);
|
||||
break;
|
||||
case 3:
|
||||
text = Text('Mer', style: style);
|
||||
break;
|
||||
case 4:
|
||||
text = Text('Jeu', style: style);
|
||||
break;
|
||||
case 5:
|
||||
text = Text('Ven', style: style);
|
||||
break;
|
||||
case 6:
|
||||
text = Text('Sam', style: style);
|
||||
break;
|
||||
default:
|
||||
text = Text('', style: style);
|
||||
break;
|
||||
}
|
||||
return SideTitleWidget(
|
||||
axisSide: meta.axisSide,
|
||||
space: 16,
|
||||
child: text,
|
||||
);
|
||||
}
|
||||
List<BarChartGroupData> showingGroups() => List.generate(7, (i) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
return makeGroupData(0, 5, TColor.primaryG , isTouched: i == touchedIndex);
|
||||
case 1:
|
||||
return makeGroupData(1, 10.5, TColor.secondaryG, isTouched: i == touchedIndex);
|
||||
case 2:
|
||||
return makeGroupData(2, 5, TColor.primaryG , isTouched: i == touchedIndex);
|
||||
case 3:
|
||||
return makeGroupData(3, 7.5, TColor.secondaryG, isTouched: i == touchedIndex);
|
||||
case 4:
|
||||
return makeGroupData(4, 15, TColor.primaryG , isTouched: i == touchedIndex);
|
||||
case 5:
|
||||
return makeGroupData(5, 5.5, TColor.secondaryG, isTouched: i == touchedIndex);
|
||||
case 6:
|
||||
return makeGroupData(6, 8.5, TColor.primaryG , isTouched: i == touchedIndex);
|
||||
default:
|
||||
return throw Error();
|
||||
}
|
||||
});
|
||||
|
||||
BarChartGroupData makeGroupData(
|
||||
int x,
|
||||
double y,
|
||||
List<Color> barColor,
|
||||
{
|
||||
bool isTouched = false,
|
||||
|
||||
double width = 22,
|
||||
List<int> showTooltips = const [],
|
||||
}) {
|
||||
|
||||
return BarChartGroupData(
|
||||
x: x,
|
||||
barRods: [
|
||||
BarChartRodData(
|
||||
toY: isTouched ? y + 1 : y,
|
||||
gradient: LinearGradient(colors: barColor, begin: Alignment.topCenter, end: Alignment.bottomCenter ),
|
||||
width: width,
|
||||
borderSide: isTouched
|
||||
? const BorderSide(color: Colors.green)
|
||||
: const BorderSide(color: Colors.white, width: 0),
|
||||
backDrawRodData: BackgroundBarChartRodData(
|
||||
show: true,
|
||||
toY: 20,
|
||||
color: TColor.lightGray,
|
||||
),
|
||||
),
|
||||
],
|
||||
showingTooltipIndicators: showTooltips,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
|
||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class BlankView extends StatefulWidget {
|
||||
const BlankView({super.key});
|
||||
|
||||
@override
|
||||
State<BlankView> createState() => _BlankViewState();
|
||||
}
|
||||
|
||||
class _BlankViewState extends State<BlankView> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: TColor.white,
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../common/colo_extension.dart';
|
||||
import '../../common_widget/notification_row.dart';
|
||||
|
||||
class NotificationView extends StatefulWidget {
|
||||
const NotificationView({super.key});
|
||||
|
||||
@override
|
||||
State<NotificationView> createState() => _NotificationViewState();
|
||||
}
|
||||
|
||||
class _NotificationViewState extends State<NotificationView> {
|
||||
List notificationArr = [
|
||||
{"image": "assets/img/workout1.svg", "title": "Hey, c'est l'heure du sport", "time": "Il y a 3 minutes"},
|
||||
{"image": "assets/img/workout1.svg", "title": "Ne manque pas ton entrainement", "time": "Il y a 7 minutes"},
|
||||
{"image": "assets/img/workout1.svg", "title": "Hey, c'est l'heure du sport", "time": "Il y a 5 jours"},
|
||||
{"image": "assets/img/workout1.svg", "title": "Ne manque pas ton entrainement", "time": "29 Mai"},
|
||||
{"image": "assets/img/workout1.svg", "title": "Hey, c'est l'heure du sport", "time": "8 Avril"},
|
||||
{"image": "assets/img/workout1.svg", "title": "Ne manque pas ton entrainement", "time": "8 Avril"},
|
||||
];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: TColor.white,
|
||||
centerTitle: true,
|
||||
elevation: 0,
|
||||
leading: InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Container(
|
||||
margin: const EdgeInsets.all(8),
|
||||
height: 40,
|
||||
width: 40,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: TColor.lightGray,
|
||||
borderRadius: BorderRadius.circular(10)),
|
||||
child: Image.asset(
|
||||
"assets/img/black_btn.png",
|
||||
width: 15,
|
||||
height: 15,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
),
|
||||
title: Text(
|
||||
"Notification",
|
||||
style: TextStyle(
|
||||
color: TColor.black, fontSize: 16, fontWeight: FontWeight.w700),
|
||||
),
|
||||
actions: [
|
||||
InkWell(
|
||||
onTap: () {},
|
||||
child: Container(
|
||||
margin: const EdgeInsets.all(8),
|
||||
height: 40,
|
||||
width: 40,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: TColor.lightGray,
|
||||
borderRadius: BorderRadius.circular(10)),
|
||||
child: Image.asset(
|
||||
"assets/img/more_btn.png",
|
||||
width: 12,
|
||||
height: 12,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
backgroundColor: TColor.white,
|
||||
body: ListView.separated(
|
||||
padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 25),
|
||||
itemBuilder: ((context, index) {
|
||||
var nObj = notificationArr[index] as Map? ?? {};
|
||||
return NotificationRow(nObj: nObj);
|
||||
}), separatorBuilder: (context, index){
|
||||
return Divider(color: TColor.gray.withOpacity(0.5), height: 1, );
|
||||
}, itemCount: notificationArr.length),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,201 @@
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
||||
import 'package:smartfit_app_mobile/common_widget/round_button.dart';
|
||||
import 'package:smartfit_app_mobile/common_widget/round_text_field.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class LoginView extends StatefulWidget {
|
||||
const LoginView({super.key});
|
||||
|
||||
@override
|
||||
State<LoginView> createState() => _LoginViewState();
|
||||
}
|
||||
|
||||
class _LoginViewState extends State<LoginView> {
|
||||
bool isCheck = false;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var media = MediaQuery.of(context).size;
|
||||
return Scaffold(
|
||||
backgroundColor: TColor.white,
|
||||
body: SingleChildScrollView(
|
||||
child: SafeArea(
|
||||
child: Container(
|
||||
height: media.height * 0.9,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
"Bienvenue,",
|
||||
style: TextStyle(color: TColor.gray, fontSize: 16),
|
||||
),
|
||||
Text(
|
||||
"Se connecter",
|
||||
style: TextStyle(
|
||||
color: TColor.black,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w700),
|
||||
),
|
||||
SizedBox(
|
||||
height: media.width * 0.05,
|
||||
),
|
||||
SizedBox(
|
||||
height: media.width * 0.04,
|
||||
),
|
||||
const RoundTextField(
|
||||
hitText: "Email",
|
||||
icon: "assets/img/email.svg",
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
),
|
||||
SizedBox(
|
||||
height: media.width * 0.04,
|
||||
),
|
||||
RoundTextField(
|
||||
hitText: "Mot de passe",
|
||||
icon: "assets/img/lock.svg",
|
||||
obscureText: true,
|
||||
rigtIcon: TextButton(
|
||||
onPressed: () {},
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: SvgPicture.asset(
|
||||
"assets/img/show_password.svg",
|
||||
width: 20,
|
||||
height: 20,
|
||||
fit: BoxFit.contain,
|
||||
))),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
"Mot de passe oublié ?",
|
||||
style: TextStyle(
|
||||
color: TColor.gray,
|
||||
fontSize: 15,
|
||||
decoration: TextDecoration.underline),
|
||||
),
|
||||
],
|
||||
),
|
||||
const Spacer(),
|
||||
RoundButton(
|
||||
title: "Se connecter",
|
||||
onPressed: () {
|
||||
|
||||
}),
|
||||
SizedBox(
|
||||
height: media.width * 0.04,
|
||||
),
|
||||
Row(
|
||||
// crossAxisAlignment: CrossAxisAlignment.,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: TColor.gray.withOpacity(0.5),
|
||||
)),
|
||||
Text(
|
||||
" Or ",
|
||||
style: TextStyle(color: TColor.black, fontSize: 12),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: TColor.gray.withOpacity(0.5),
|
||||
)),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: media.width * 0.04,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {},
|
||||
child: Container(
|
||||
width: 50,
|
||||
height: 50,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: TColor.white,
|
||||
border: Border.all(
|
||||
width: 1,
|
||||
color: TColor.gray.withOpacity(0.4),
|
||||
),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Image.asset(
|
||||
"assets/img/google.png",
|
||||
width: 20,
|
||||
height: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: media.width * 0.04,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {},
|
||||
child: Container(
|
||||
width: 50,
|
||||
height: 50,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: TColor.white,
|
||||
border: Border.all(
|
||||
width: 1,
|
||||
color: TColor.gray.withOpacity(0.4),
|
||||
),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Image.asset(
|
||||
"assets/img/suunto.png",
|
||||
width: 35,
|
||||
height: 35,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: media.width * 0.04,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
"Vous n'avez pas toujours pas de compte ? ",
|
||||
style: TextStyle(
|
||||
color: TColor.black,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"Créer un compte",
|
||||
style: TextStyle(
|
||||
color: TColor.black,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w700),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: media.width * 0.04,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,233 @@
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
||||
import 'package:smartfit_app_mobile/common_widget/round_button.dart';
|
||||
import 'package:smartfit_app_mobile/common_widget/round_text_field.dart';
|
||||
import 'package:smartfit_app_mobile/view/home/home_view.dart';
|
||||
//import 'package:smartfit_app_mobile/view/login/complete_profile_view.dart';
|
||||
import 'package:smartfit_app_mobile/view/login/login_view.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:smartfit_app_mobile/view/main_tab/main_tab_view.dart';
|
||||
|
||||
class SignUpView extends StatefulWidget {
|
||||
const SignUpView({super.key});
|
||||
|
||||
@override
|
||||
State<SignUpView> createState() => _SignUpViewState();
|
||||
}
|
||||
|
||||
class _SignUpViewState extends State<SignUpView> {
|
||||
bool isCheck = false;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var media = MediaQuery.of(context).size;
|
||||
return Scaffold(
|
||||
backgroundColor: TColor.white,
|
||||
body: SingleChildScrollView(
|
||||
child: SafeArea(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
"Bienvenue,",
|
||||
style: TextStyle(color: TColor.gray, fontSize: 16),
|
||||
),
|
||||
Text(
|
||||
"Créer un compte",
|
||||
style: TextStyle(
|
||||
color: TColor.black,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w700),
|
||||
),
|
||||
SizedBox(
|
||||
height: media.width * 0.05,
|
||||
),
|
||||
const RoundTextField(
|
||||
hitText: "Prénom",
|
||||
icon: "assets/img/user_text.svg",
|
||||
),
|
||||
SizedBox(
|
||||
height: media.width * 0.04,
|
||||
),
|
||||
const RoundTextField(
|
||||
hitText: "Nom",
|
||||
icon: "assets/img/user_text.svg",
|
||||
),
|
||||
SizedBox(
|
||||
height: media.width * 0.04,
|
||||
),
|
||||
const RoundTextField(
|
||||
hitText: "Email",
|
||||
icon: "assets/img/email.svg",
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
),
|
||||
SizedBox(
|
||||
height: media.width * 0.04,
|
||||
),
|
||||
RoundTextField(
|
||||
hitText: "Mot de passe",
|
||||
icon: "assets/img/lock.svg",
|
||||
obscureText: true,
|
||||
rigtIcon: TextButton(
|
||||
onPressed: () {},
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: SvgPicture.asset(
|
||||
"assets/img/show_password.svg",
|
||||
width: 20,
|
||||
height: 20,
|
||||
fit: BoxFit.contain,
|
||||
))),
|
||||
),
|
||||
Row(
|
||||
// crossAxisAlignment: CrossAxisAlignment.,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isCheck = !isCheck;
|
||||
});
|
||||
},
|
||||
icon: Icon(
|
||||
isCheck
|
||||
? Icons.check_box_outlined
|
||||
: Icons.check_box_outline_blank_outlined,
|
||||
color: TColor.gray,
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: Text(
|
||||
"En continuant, vous acceptez notre Politique de\nconfidentialité et nos Conditions d'utilisation.",
|
||||
style: TextStyle(color: TColor.gray, fontSize: 10),
|
||||
),
|
||||
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: media.width * 0.4,
|
||||
),
|
||||
RoundButton(title: "Créer un compte", onPressed: () {}),
|
||||
SizedBox(
|
||||
height: media.width * 0.04,
|
||||
),
|
||||
Row(
|
||||
// crossAxisAlignment: CrossAxisAlignment.,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: TColor.gray.withOpacity(0.5),
|
||||
)),
|
||||
Text(
|
||||
" Ou ",
|
||||
style: TextStyle(color: TColor.black, fontSize: 12),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: TColor.gray.withOpacity(0.5),
|
||||
)),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: media.width * 0.04,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {},
|
||||
child: Container(
|
||||
width: 50,
|
||||
height: 50,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: TColor.white,
|
||||
border: Border.all(
|
||||
width: 1,
|
||||
color: TColor.gray.withOpacity(0.4),
|
||||
),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Image.asset(
|
||||
"assets/img/google.png",
|
||||
width: 20,
|
||||
height: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
width: media.width * 0.04,
|
||||
),
|
||||
|
||||
GestureDetector(
|
||||
onTap: () {},
|
||||
child: Container(
|
||||
width: 50,
|
||||
height: 50,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: TColor.white,
|
||||
border: Border.all(
|
||||
width: 1,
|
||||
color: TColor.gray.withOpacity(0.4),
|
||||
),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Image.asset(
|
||||
"assets/img/suunto.png",
|
||||
width: 35,
|
||||
height: 35,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: media.width * 0.04,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const MainTabView()));
|
||||
},
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
"Vous avez déjà un compte ? ",
|
||||
style: TextStyle(
|
||||
color: TColor.black,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"Se connecter",
|
||||
style: TextStyle(
|
||||
color: TColor.black,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w700),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: media.width * 0.04,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
||||
import 'package:smartfit_app_mobile/common_widget/tab_button.dart';
|
||||
import 'package:smartfit_app_mobile/view/activity/activity.dart';
|
||||
import 'package:smartfit_app_mobile/view/home/blank_view.dart';
|
||||
import 'package:smartfit_app_mobile/view/home/home_view.dart';
|
||||
import 'package:smartfit_app_mobile/view/main_tab/select_view.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:smartfit_app_mobile/view/map/my_map.dart';
|
||||
import 'package:smartfit_app_mobile/view/page_test.dart';
|
||||
import 'package:smartfit_app_mobile/view/profile/profile_view.dart';
|
||||
|
||||
|
||||
|
||||
class MainTabView extends StatefulWidget {
|
||||
const MainTabView({super.key});
|
||||
|
||||
@override
|
||||
State<MainTabView> createState() => _MainTabViewState();
|
||||
}
|
||||
|
||||
class _MainTabViewState extends State<MainTabView> {
|
||||
int selectTab = 0;
|
||||
final PageStorageBucket pageBucket = PageStorageBucket();
|
||||
Widget currentTab = const HomeView();
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: TColor.white,
|
||||
body: PageStorage(bucket: pageBucket, child: currentTab),
|
||||
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
|
||||
floatingActionButton: SizedBox(
|
||||
width: 70,
|
||||
height: 70,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
selectTab = 0;
|
||||
currentTab = const TestPage();
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
width: 65,
|
||||
height: 65,
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: TColor.primaryG,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(35),
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: Colors.black12,
|
||||
blurRadius: 2,)
|
||||
]),
|
||||
child: Icon(Icons.search,color: TColor.white, size: 35, ),
|
||||
),
|
||||
),
|
||||
),
|
||||
bottomNavigationBar: BottomAppBar(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(color: TColor.white, boxShadow: const [
|
||||
BoxShadow(color: Colors.black12, blurRadius: 2, offset: Offset(0, -2))
|
||||
]),
|
||||
height: kToolbarHeight,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
TabButton(
|
||||
icon: "assets/img/Home_tab.svg",
|
||||
selectIcon: "assets/img/Home_tab_select.svg",
|
||||
isActive: selectTab == 0,
|
||||
onTap: () {
|
||||
selectTab = 0;
|
||||
currentTab = const HomeView();
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
}),
|
||||
TabButton(
|
||||
icon: "assets/img/Activity_tab.svg",
|
||||
selectIcon: "assets/img/Activity_tab_select.svg",
|
||||
isActive: selectTab == 1,
|
||||
onTap: () {
|
||||
selectTab = 1;
|
||||
currentTab = const Activity();
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
}),
|
||||
|
||||
const SizedBox(width: 40,),
|
||||
TabButton(
|
||||
icon: "assets/img/Camera_tab.svg",
|
||||
selectIcon: "assets/img/Camera_tab_select.svg",
|
||||
isActive: selectTab == 2,
|
||||
onTap: () {
|
||||
selectTab = 2;
|
||||
currentTab = const MyMap();
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
}),
|
||||
TabButton(
|
||||
icon: "assets/img/Profile_tab.svg",
|
||||
selectIcon: "assets/img/Profile_tab_select.svg",
|
||||
isActive: selectTab == 3,
|
||||
onTap: () {
|
||||
selectTab = 3;
|
||||
currentTab = const ProfileView();
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
],
|
||||
),
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
import 'package:smartfit_app_mobile/common_widget/round_button.dart';
|
||||
//import 'package:smartfit_app_mobile/view/meal_planner/meal_planner_view.dart';
|
||||
//import 'package:smartfit_app_mobile/view/workout_tracker/workout_tracker_view.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:smartfit_app_mobile/view/home/blank_view.dart';
|
||||
|
||||
//import '../sleep_tracker/sleep_tracker_view.dart';
|
||||
|
||||
class SelectView extends StatelessWidget {
|
||||
const SelectView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// var media = MediaQuery.of(context).size;
|
||||
|
||||
return Scaffold(
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
RoundButton(
|
||||
title: "Workout Tracker",
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const BlankView(),
|
||||
),
|
||||
);
|
||||
}),
|
||||
|
||||
const SizedBox(height: 15,),
|
||||
|
||||
RoundButton(
|
||||
title: "Meal Planner",
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const BlankView(),
|
||||
),
|
||||
);
|
||||
}),
|
||||
|
||||
const SizedBox(height: 15,),
|
||||
|
||||
RoundButton(
|
||||
title: "Sleep Tracker",
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const BlankView(),
|
||||
),
|
||||
);
|
||||
})
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,154 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import 'package:location/location.dart';
|
||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
||||
|
||||
class MyMap extends StatefulWidget {
|
||||
const MyMap({ Key? key }) : super(key: key);
|
||||
|
||||
@override
|
||||
State<MyMap> createState() => _MyMapState();
|
||||
}
|
||||
|
||||
class _MyMapState extends State<MyMap> {
|
||||
|
||||
Completer<GoogleMapController> _googleMapController = Completer();
|
||||
CameraPosition? _cameraPosition;
|
||||
Location? _location;
|
||||
LocationData? _currentLocation;
|
||||
List<LatLng> _polylineCoordinates = [];
|
||||
Set<Polyline> _polylines = {};
|
||||
Set<Marker> _markers = {}; // Add a set to store markers
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_init();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
_init() async {
|
||||
_location = Location();
|
||||
_cameraPosition = CameraPosition(
|
||||
target: LatLng(0, 0), // this is just the example lat and lng for initializing
|
||||
zoom: 20
|
||||
);
|
||||
_initLocation();
|
||||
}
|
||||
|
||||
//function to listen when we move position
|
||||
_initLocation() {
|
||||
|
||||
_location?.getLocation().then((location) {
|
||||
_currentLocation = location;
|
||||
});
|
||||
|
||||
_location?.onLocationChanged.listen((newLocation) {
|
||||
setState(() {
|
||||
_currentLocation = newLocation;
|
||||
_polylineCoordinates.add(LatLng(
|
||||
_currentLocation?.latitude ?? 0,
|
||||
_currentLocation?.longitude ?? 0,
|
||||
));
|
||||
_updatePolyline();
|
||||
|
||||
});
|
||||
|
||||
moveToPosition(LatLng(_currentLocation?.latitude ?? 0,
|
||||
_currentLocation?.longitude ?? 0));
|
||||
});
|
||||
}
|
||||
|
||||
_updatePolyline() {
|
||||
setState(() {
|
||||
_polylines.clear();
|
||||
_polylines.add(Polyline(
|
||||
polylineId: PolylineId("polyline"),
|
||||
color: TColor.primaryColor1,
|
||||
points: _polylineCoordinates,
|
||||
width: 10,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
// Updated _updateMarker to use the custom marker
|
||||
_updateMarker(LatLng position) async {
|
||||
final markerId = MarkerId('marker');
|
||||
final marker = Marker(
|
||||
markerId: markerId,
|
||||
position: position
|
||||
);
|
||||
_markers.clear();
|
||||
_markers.add(marker);
|
||||
}
|
||||
|
||||
|
||||
moveToPosition(LatLng latLng) async {
|
||||
GoogleMapController mapController = await _googleMapController.future;
|
||||
mapController.animateCamera(
|
||||
CameraUpdate.newCameraPosition(
|
||||
CameraPosition(
|
||||
target: latLng,
|
||||
zoom: 15
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: _buildBody(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody() {
|
||||
return _getMap();
|
||||
}
|
||||
|
||||
Widget _getMarker() {
|
||||
return Container(
|
||||
width: 25,
|
||||
height: 25,
|
||||
padding: EdgeInsets.all(2),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey,
|
||||
offset: Offset(0,3),
|
||||
spreadRadius: 4,
|
||||
blurRadius: 6
|
||||
)
|
||||
]
|
||||
),
|
||||
child: ClipOval(child: Image.asset("assets/img/u1.png")),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _getMap() {
|
||||
return Stack(
|
||||
children: [
|
||||
GoogleMap(
|
||||
initialCameraPosition: _cameraPosition!,
|
||||
mapType: MapType.normal,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
if (!_googleMapController.isCompleted) {
|
||||
_googleMapController.complete(controller);
|
||||
}
|
||||
},
|
||||
polylines: _polylines,
|
||||
markers: _markers,
|
||||
),
|
||||
Positioned.fill(
|
||||
child: Align(
|
||||
alignment: Alignment.center,
|
||||
child: _getMarker()
|
||||
)
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import 'package:location/location.dart';
|
||||
|
||||
class MyMap extends StatefulWidget {
|
||||
const MyMap({ Key? key }) : super(key: key);
|
||||
|
||||
@override
|
||||
State<MyMap> createState() => _MyMapState();
|
||||
}
|
||||
|
||||
class _MyMapState extends State<MyMap> {
|
||||
|
||||
Completer<GoogleMapController> _googleMapController = Completer();
|
||||
CameraPosition? _cameraPosition;
|
||||
Location? _location;
|
||||
LocationData? _currentLocation;
|
||||
|
||||
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_init();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
_init() async {
|
||||
_location = Location();
|
||||
_cameraPosition = CameraPosition(
|
||||
target: LatLng(0, 0), // this is just the example lat and lng for initializing
|
||||
zoom: 15
|
||||
);
|
||||
_initLocation();
|
||||
}
|
||||
|
||||
//function to listen when we move position
|
||||
_initLocation() {
|
||||
//use this to go to current location instead
|
||||
_location?.getLocation().then((location) {
|
||||
_currentLocation = location;
|
||||
});
|
||||
_location?.onLocationChanged.listen((newLocation) {
|
||||
_currentLocation = newLocation;
|
||||
moveToPosition(LatLng(_currentLocation?.latitude ?? 0, _currentLocation?.longitude ?? 0));
|
||||
});
|
||||
}
|
||||
|
||||
moveToPosition(LatLng latLng) async {
|
||||
GoogleMapController mapController = await _googleMapController.future;
|
||||
mapController.animateCamera(
|
||||
CameraUpdate.newCameraPosition(
|
||||
CameraPosition(
|
||||
target: latLng,
|
||||
zoom: 15
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: _buildBody(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody() {
|
||||
return _getMap();
|
||||
}
|
||||
|
||||
Widget _getMarker() {
|
||||
return Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
padding: EdgeInsets.all(2),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey,
|
||||
offset: Offset(0,3),
|
||||
spreadRadius: 4,
|
||||
blurRadius: 6
|
||||
)
|
||||
]
|
||||
),
|
||||
child: ClipOval(child: Image.asset("assets/img/u1.png")),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _getMap() {
|
||||
return Stack(
|
||||
children: [
|
||||
GoogleMap(
|
||||
initialCameraPosition: _cameraPosition!,
|
||||
mapType: MapType.normal,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
// now we need a variable to get the controller of google map
|
||||
if (!_googleMapController.isCompleted) {
|
||||
_googleMapController.complete(controller);
|
||||
}
|
||||
},
|
||||
),
|
||||
|
||||
Positioned.fill(
|
||||
child: Align(
|
||||
alignment: Alignment.center,
|
||||
child: _getMarker()
|
||||
)
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
||||
import 'package:smartfit_app_mobile/common_widget/on_boarding_page.dart';
|
||||
import 'package:smartfit_app_mobile/view/login/signup_view.dart';
|
||||
|
||||
class OnBoardingView extends StatefulWidget {
|
||||
const OnBoardingView({super.key});
|
||||
|
||||
@override
|
||||
State<OnBoardingView> createState() => _OnBoardingViewState();
|
||||
}
|
||||
|
||||
class _OnBoardingViewState extends State<OnBoardingView> {
|
||||
int selectPage = 0;
|
||||
PageController controller = PageController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
||||
super.initState();
|
||||
|
||||
controller.addListener(() {
|
||||
selectPage = controller.page?.round() ?? 0;
|
||||
|
||||
setState(() {
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
List pageArr = [
|
||||
{
|
||||
"title": "Atteignez vos objectifs",
|
||||
"subtitle":
|
||||
"Ne vous inquiétez pas si vous avez du mal à déterminer vos objectifs. Grâce à l'analyse concrète de vos performances, nous vous aiderons à les atteindre.",
|
||||
"image": "assets/img/on_1.svg"
|
||||
},
|
||||
{
|
||||
"title": "Persévérez",
|
||||
"subtitle":
|
||||
"Continuez à persévérer pour atteindre vos objectifs. La douleur n'est que temporaire. Si vous abandonnez maintenant, vous souffrirez éternellement.",
|
||||
"image": "assets/img/on_2.svg"
|
||||
},
|
||||
{
|
||||
"title": "Laissez-nous piloter, mettez simplement votre Suunto",
|
||||
"subtitle":
|
||||
"Détendez-vous, nous prenons les commandes en analysant performances et statistiques pour vous aider à atteindre vos objectifs.",
|
||||
"image": "assets/img/on_3.svg"
|
||||
},
|
||||
];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: TColor.white,
|
||||
body: Stack(
|
||||
alignment: Alignment.bottomRight,
|
||||
children: [
|
||||
PageView.builder(
|
||||
controller: controller,
|
||||
itemCount: pageArr.length,
|
||||
itemBuilder: (context, index) {
|
||||
var pObj = pageArr[index] as Map? ?? {};
|
||||
return OnBoardingPage(pObj: pObj) ;
|
||||
}),
|
||||
|
||||
SizedBox(
|
||||
width: 120,
|
||||
height: 120,
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
|
||||
SizedBox(
|
||||
width: 70,
|
||||
height: 70,
|
||||
child: CircularProgressIndicator(
|
||||
color: TColor.primaryColor1,
|
||||
value: (selectPage + 1) / 3 ,
|
||||
strokeWidth: 2,
|
||||
),
|
||||
),
|
||||
|
||||
Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 30, vertical: 30),
|
||||
width: 60,
|
||||
height: 60,
|
||||
decoration: BoxDecoration(color: TColor.primaryColor1, borderRadius: BorderRadius.circular(35)),
|
||||
child: IconButton(icon: Icon( Icons.navigate_next, color: TColor.white, ), onPressed: (){
|
||||
|
||||
if(selectPage < 2) {
|
||||
selectPage = selectPage + 1;
|
||||
controller.animateToPage(selectPage, duration: const Duration(milliseconds: 200), curve: Curves.bounceInOut);
|
||||
setState(() {
|
||||
|
||||
});
|
||||
|
||||
}else{
|
||||
Navigator.push(context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const SignUpView()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
},),
|
||||
),
|
||||
|
||||
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
||||
import 'package:smartfit_app_mobile/view/on_boarding/on_boarding_view.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../common_widget/round_button.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
||||
class StartedView extends StatefulWidget {
|
||||
const StartedView({super.key});
|
||||
|
||||
@override
|
||||
State<StartedView> createState() => _StartedViewState();
|
||||
}
|
||||
|
||||
class _StartedViewState extends State<StartedView> {
|
||||
bool isChangeColor = true;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var media = MediaQuery.of(context).size;
|
||||
return Scaffold(
|
||||
backgroundColor: TColor.white,
|
||||
body: Container(
|
||||
width: media.width,
|
||||
decoration: BoxDecoration(
|
||||
gradient: isChangeColor
|
||||
? LinearGradient(
|
||||
colors: TColor.primaryG,
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight)
|
||||
: null,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: media.width * 0.90,
|
||||
),
|
||||
SvgPicture.asset("assets/img/logoSM.svg"),
|
||||
const Spacer(),
|
||||
SafeArea(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||
child: RoundButton(
|
||||
title: "Commencer",
|
||||
type: isChangeColor
|
||||
? RoundButtonType.textGradient
|
||||
: RoundButtonType.bgGradient,
|
||||
onPressed: () {
|
||||
if (isChangeColor) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const OnBoardingView()));
|
||||
} else {
|
||||
//Change Color
|
||||
setState(() {
|
||||
isChangeColor = true;
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,354 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../common/colo_extension.dart';
|
||||
import '../../common_widget/round_button.dart';
|
||||
import '../../common_widget/setting_row.dart';
|
||||
import '../../common_widget/title_subtitle_cell.dart';
|
||||
import 'package:animated_toggle_switch/animated_toggle_switch.dart';
|
||||
|
||||
class ProfileView extends StatefulWidget {
|
||||
const ProfileView({super.key});
|
||||
|
||||
@override
|
||||
State<ProfileView> createState() => _ProfileViewState();
|
||||
}
|
||||
|
||||
class _ProfileViewState extends State<ProfileView> {
|
||||
bool positive = false;
|
||||
|
||||
List accountArr = [
|
||||
{"image": "assets/img/p_personal.png", "name": "Données personnelles", "tag": "1"},
|
||||
|
||||
];
|
||||
|
||||
List otherArr = [
|
||||
{"image": "assets/img/p_contact.png", "name": "Nous contacter", "tag": "5"},
|
||||
{"image": "assets/img/p_privacy.png", "name": "Politique de confidentialité", "tag": "6"},
|
||||
];
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: TColor.white,
|
||||
centerTitle: true,
|
||||
elevation: 0,
|
||||
leadingWidth: 0,
|
||||
title: Text(
|
||||
"Profile",
|
||||
style: TextStyle(
|
||||
color: TColor.black, fontSize: 16, fontWeight: FontWeight.w700),
|
||||
),
|
||||
actions: [
|
||||
InkWell(
|
||||
onTap: () {},
|
||||
child: Container(
|
||||
margin: const EdgeInsets.all(8),
|
||||
height: 20,
|
||||
width: 20,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: TColor.lightGray,
|
||||
borderRadius: BorderRadius.circular(10)),
|
||||
child: Image.asset(
|
||||
"assets/img/more_btn.png",
|
||||
width: 15,
|
||||
height: 15,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
backgroundColor: TColor.white,
|
||||
body: SingleChildScrollView(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 25),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
child: Image.asset(
|
||||
"assets/img/u1.png",
|
||||
width: 50,
|
||||
height: 50,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 15,
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Benjelloun Othmane",
|
||||
style: TextStyle(
|
||||
color: TColor.black,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"Course à pied",
|
||||
style: TextStyle(
|
||||
color: TColor.gray,
|
||||
fontSize: 12,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 70,
|
||||
height: 25,
|
||||
child: RoundButton(
|
||||
title: "Editer",
|
||||
type: RoundButtonType.bgGradient,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
onPressed: () {
|
||||
// Navigator.push(
|
||||
// context,
|
||||
// MaterialPageRoute(
|
||||
// builder: (context) => const ActivityTrackerView(),
|
||||
// ),
|
||||
// );
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
const Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TitleSubtitleCell(
|
||||
title: "??? cm",
|
||||
subtitle: "Taille",
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 15,
|
||||
),
|
||||
Expanded(
|
||||
child: TitleSubtitleCell(
|
||||
title: "?? kg",
|
||||
subtitle: "Poids",
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 15,
|
||||
),
|
||||
Expanded(
|
||||
child: TitleSubtitleCell(
|
||||
title: "?? ans",
|
||||
subtitle: "Age",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 25,
|
||||
),
|
||||
Container(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
|
||||
decoration: BoxDecoration(
|
||||
color: TColor.white,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
boxShadow: const [
|
||||
BoxShadow(color: Colors.black12, blurRadius: 2)
|
||||
]),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Compte",
|
||||
style: TextStyle(
|
||||
color: TColor.black,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
ListView.builder(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
itemCount: accountArr.length,
|
||||
itemBuilder: (context, index) {
|
||||
var iObj = accountArr[index] as Map? ?? {};
|
||||
return SettingRow(
|
||||
icon: iObj["image"].toString(),
|
||||
title: iObj["name"].toString(),
|
||||
onPressed: () {},
|
||||
);
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 25,
|
||||
),
|
||||
Container(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
|
||||
decoration: BoxDecoration(
|
||||
color: TColor.white,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
boxShadow: const [
|
||||
BoxShadow(color: Colors.black12, blurRadius: 2)
|
||||
]),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Notification",
|
||||
style: TextStyle(
|
||||
color: TColor.black,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
SizedBox(
|
||||
height: 30,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Image.asset("assets/img/p_notification.png",
|
||||
height: 15, width: 15, fit: BoxFit.contain),
|
||||
const SizedBox(
|
||||
width: 15,
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
"Pop-up Notification",
|
||||
style: TextStyle(
|
||||
color: TColor.black,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
),
|
||||
CustomAnimatedToggleSwitch<bool>(
|
||||
current: positive,
|
||||
values: [false, true],
|
||||
spacing : 0.0,
|
||||
indicatorSize: Size.square(25.0),
|
||||
animationDuration:
|
||||
const Duration(milliseconds: 200),
|
||||
animationCurve: Curves.linear,
|
||||
onChanged: (b) => setState(() => positive = b),
|
||||
iconBuilder: (context, local, global) {
|
||||
return const SizedBox();
|
||||
},
|
||||
cursors: ToggleCursors(defaultCursor: SystemMouseCursors.click),
|
||||
onTap: (_) => setState(() => positive = !positive),
|
||||
iconsTappable: false,
|
||||
wrapperBuilder: (context, global, child) {
|
||||
return Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Positioned(
|
||||
left: 10.0,
|
||||
right: 10.0,
|
||||
|
||||
height: 20.0,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: TColor.secondaryG),
|
||||
borderRadius:
|
||||
const BorderRadius.all(
|
||||
Radius.circular(50.0)),
|
||||
),
|
||||
)),
|
||||
child,
|
||||
],
|
||||
);
|
||||
},
|
||||
foregroundIndicatorBuilder: (context, global) {
|
||||
return SizedBox.fromSize(
|
||||
size: const Size(5, 5),
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: TColor.white,
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(50.0)),
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: Colors.black38,
|
||||
spreadRadius: 0.05,
|
||||
blurRadius: 1.1,
|
||||
offset: Offset(0.0, 0.8))
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
]),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 25,
|
||||
),
|
||||
Container(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
|
||||
decoration: BoxDecoration(
|
||||
color: TColor.white,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
boxShadow: const [
|
||||
BoxShadow(color: Colors.black12, blurRadius: 2)
|
||||
]),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Autre",
|
||||
style: TextStyle(
|
||||
color: TColor.black,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
ListView.builder(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
padding: EdgeInsets.zero,
|
||||
shrinkWrap: true,
|
||||
itemCount: otherArr.length,
|
||||
itemBuilder: (context, index) {
|
||||
var iObj = otherArr[index] as Map? ?? {};
|
||||
return SettingRow(
|
||||
icon: iObj["image"].toString(),
|
||||
title: iObj["name"].toString(),
|
||||
onPressed: () {},
|
||||
);
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class TColor {
|
||||
static Color get primaryColor1 => Color(0xffF09932);
|
||||
static Color get primaryColor2 => Color(0xffFFDCB2);
|
||||
|
||||
static Color get secondaryColor1 => Color(0xff6131AD);
|
||||
static Color get secondaryColor2 => Color(0xffD4B9FF);
|
||||
|
||||
static List<Color> get primaryG => [ primaryColor2, primaryColor1 ];
|
||||
static List<Color> get secondaryG => [secondaryColor2, secondaryColor1];
|
||||
|
||||
static Color get black => const Color(0xff1D1617);
|
||||
static Color get gray => const Color(0xff786F72);
|
||||
static Color get white => Colors.white;
|
||||
static Color get lightGray => const Color(0xffF7F8F8);
|
||||
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
||||
import 'package:smartfit_app_mobile/common_widget/helpers.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class Dates extends StatelessWidget {
|
||||
const Dates({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
List<DateBox> dateBoxes = [];
|
||||
|
||||
// DateTime date = DateTime.parse('2021-11-08');
|
||||
DateTime date = DateTime.now().subtract(const Duration(days: 3));
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
dateBoxes.add(DateBox(date: date, active: i == 3));
|
||||
date = date.add(const Duration(days: 1));
|
||||
}
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: dateBoxes,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DateBox extends StatelessWidget {
|
||||
final bool active;
|
||||
final DateTime date;
|
||||
|
||||
const DateBox({
|
||||
Key? key,
|
||||
this.active = false,
|
||||
required this.date,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: 50,
|
||||
height: 70,
|
||||
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 5),
|
||||
decoration: BoxDecoration(
|
||||
gradient: active
|
||||
? LinearGradient(colors: [
|
||||
TColor.primaryColor2,
|
||||
TColor.primaryColor1,
|
||||
], begin: Alignment.topCenter)
|
||||
: null,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(
|
||||
color: const Color(0xffe1e1e1),
|
||||
),
|
||||
),
|
||||
child: DefaultTextStyle.merge(
|
||||
style: active ? const TextStyle(color: Colors.white) : null,
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
daysOfWeek[date.weekday]!,
|
||||
style: const TextStyle(
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(date.day.toString().padLeft(2, '0'),
|
||||
style: const TextStyle(
|
||||
fontSize: 19,
|
||||
fontWeight: FontWeight.w500,
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,187 @@
|
||||
import 'dart:math';
|
||||
import 'dart:ui' as ui;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
||||
|
||||
class Graph extends StatelessWidget {
|
||||
const Graph({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Expanded(
|
||||
child: SizedBox(
|
||||
width: double.infinity,
|
||||
child: GraphArea(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class GraphArea extends StatefulWidget {
|
||||
const GraphArea({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_GraphAreaState createState() => _GraphAreaState();
|
||||
}
|
||||
|
||||
class _GraphAreaState extends State<GraphArea>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late AnimationController _animationController;
|
||||
|
||||
List<DataPoint> data = [
|
||||
DataPoint(day: 1, steps: Random().nextInt(70)),
|
||||
DataPoint(day: 2, steps: Random().nextInt(70)),
|
||||
DataPoint(day: 3, steps: Random().nextInt(70)),
|
||||
DataPoint(day: 4, steps: Random().nextInt(70)),
|
||||
DataPoint(day: 5, steps: Random().nextInt(70)),
|
||||
DataPoint(day: 6, steps: Random().nextInt(70)),
|
||||
DataPoint(day: 7, steps: Random().nextInt(70)),
|
||||
DataPoint(day: 8, steps: Random().nextInt(70)),
|
||||
];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_animationController = AnimationController(
|
||||
vsync: this, duration: const Duration(milliseconds: 2500));
|
||||
_animationController.forward();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_animationController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
_animationController.forward(from: 0.0);
|
||||
},
|
||||
child: CustomPaint(
|
||||
painter: GraphPainter(_animationController.view, data: data),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class GraphPainter extends CustomPainter {
|
||||
final List<DataPoint> data;
|
||||
final Animation<double> _size;
|
||||
final Animation<double> _dotSize;
|
||||
|
||||
GraphPainter(Animation<double> animation, {required this.data})
|
||||
: _size = Tween<double>(begin: 0, end: 1).animate(
|
||||
CurvedAnimation(
|
||||
parent: animation,
|
||||
curve: const Interval(0.0, 0.75,
|
||||
curve: Curves.easeInOutCubicEmphasized),
|
||||
),
|
||||
),
|
||||
_dotSize = Tween<double>(begin: 0, end: 1).animate(
|
||||
CurvedAnimation(
|
||||
parent: animation,
|
||||
curve:
|
||||
const Interval(0.75, 1, curve: Curves.easeInOutCubicEmphasized),
|
||||
),
|
||||
),
|
||||
super(repaint: animation);
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
var xSpacing = size.width / (data.length - 1);
|
||||
|
||||
var maxSteps = data
|
||||
.fold<DataPoint>(data[0], (p, c) => p.steps > c.steps ? p : c)
|
||||
.steps;
|
||||
|
||||
var yRatio = size.height / maxSteps;
|
||||
var curveOffset = xSpacing * 0.3;
|
||||
|
||||
List<Offset> offsets = [];
|
||||
|
||||
var cx = 0.0;
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
var y = size.height - (data[i].steps * yRatio * _size.value);
|
||||
|
||||
offsets.add(Offset(cx, y));
|
||||
cx += xSpacing;
|
||||
}
|
||||
|
||||
Paint linePaint = Paint()
|
||||
..color = TColor.primaryColor1
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 2;
|
||||
|
||||
Paint shadowPaint = Paint()
|
||||
..color = TColor.primaryColor1
|
||||
..style = PaintingStyle.stroke
|
||||
..maskFilter = const ui.MaskFilter.blur(ui.BlurStyle.solid, 0)
|
||||
..strokeWidth = 0.0;
|
||||
|
||||
Paint fillPaint = Paint()
|
||||
..shader = ui.Gradient.linear(
|
||||
Offset(size.width / 2, 0),
|
||||
Offset(size.width / 2, size.height),
|
||||
[
|
||||
TColor.primaryColor1,
|
||||
Colors.white,
|
||||
],
|
||||
)
|
||||
..color = TColor.primaryColor1
|
||||
..style = PaintingStyle.fill;
|
||||
|
||||
Paint dotOutlinePaint = Paint()
|
||||
..color = Colors.white.withAlpha(200)
|
||||
..strokeWidth = 8;
|
||||
|
||||
Paint dotCenter = Paint()
|
||||
..color = TColor.primaryColor1
|
||||
..strokeWidth = 8;
|
||||
|
||||
Path linePath = Path();
|
||||
|
||||
Offset cOffset = offsets[0];
|
||||
|
||||
linePath.moveTo(cOffset.dx, cOffset.dy);
|
||||
|
||||
for (int i = 1; i < offsets.length; i++) {
|
||||
var x = offsets[i].dx;
|
||||
var y = offsets[i].dy;
|
||||
var c1x = cOffset.dx + curveOffset;
|
||||
var c1y = cOffset.dy;
|
||||
var c2x = x - curveOffset;
|
||||
var c2y = y;
|
||||
|
||||
linePath.cubicTo(c1x, c1y, c2x, c2y, x, y);
|
||||
cOffset = offsets[i];
|
||||
}
|
||||
|
||||
Path fillPath = Path.from(linePath);
|
||||
fillPath.lineTo(size.width, size.height);
|
||||
fillPath.lineTo(0, size.height);
|
||||
|
||||
canvas.drawPath(fillPath, fillPaint);
|
||||
canvas.drawPath(linePath, shadowPaint);
|
||||
canvas.drawPath(linePath, linePaint);
|
||||
|
||||
canvas.drawCircle(offsets[4], 15 * _dotSize.value, dotOutlinePaint);
|
||||
canvas.drawCircle(offsets[4], 6 * _dotSize.value, dotCenter);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant GraphPainter oldDelegate) {
|
||||
return data != oldDelegate.data;
|
||||
}
|
||||
}
|
||||
|
||||
class DataPoint {
|
||||
final int day;
|
||||
final int steps;
|
||||
|
||||
DataPoint({
|
||||
required this.day,
|
||||
required this.steps,
|
||||
});
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
import 'dart:math';
|
||||
|
||||
final Map<int, String> daysOfWeek = {
|
||||
1: 'Mon',
|
||||
2: 'Tue',
|
||||
3: 'Wed',
|
||||
4: 'Thu',
|
||||
5: 'Fri',
|
||||
6: 'Sat',
|
||||
7: 'Sun',
|
||||
};
|
||||
|
||||
int randBetween(int min, int max) {
|
||||
return Random().nextInt(max - min) + min;
|
||||
}
|
||||
|
||||
String formatNumber(int number) {
|
||||
return number.toString().replaceAllMapped(
|
||||
RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'),
|
||||
(Match m) => '${m[1]},',
|
||||
);
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class Info extends StatelessWidget {
|
||||
const Info({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: const [
|
||||
Stats(value: '345', unit: 'kcal', label: 'Calories'),
|
||||
Stats(value: '3.6', unit: 'km', label: 'Distance'),
|
||||
Stats(value: '1.5', unit: 'hr', label: 'Hours'),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Stats extends StatelessWidget {
|
||||
final String value;
|
||||
final String unit;
|
||||
final String label;
|
||||
|
||||
const Stats({
|
||||
Key? key,
|
||||
required this.value,
|
||||
required this.unit,
|
||||
required this.label,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
text: value,
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
children: [
|
||||
const TextSpan(text: ' '),
|
||||
TextSpan(
|
||||
text: unit,
|
||||
style: const TextStyle(
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
]),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class LatestActivityRow extends StatelessWidget {
|
||||
final Map wObj;
|
||||
const LatestActivityRow({super.key, required this.wObj});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.symmetric(vertical: 8),
|
||||
|
||||
child: Row(
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
child: SvgPicture.asset(
|
||||
wObj["image"].toString(),
|
||||
width: 50,
|
||||
height: 50,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(width: 15,),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
wObj["title"].toString(),
|
||||
style: TextStyle(
|
||||
color: TColor.black,
|
||||
fontSize: 12, fontWeight: FontWeight.w500),
|
||||
),
|
||||
|
||||
Text(
|
||||
wObj["time"].toString(),
|
||||
style: TextStyle(
|
||||
color: TColor.gray,
|
||||
fontSize: 10,),
|
||||
),
|
||||
|
||||
|
||||
|
||||
],
|
||||
)),
|
||||
IconButton(
|
||||
onPressed: () {},
|
||||
icon: Image.asset(
|
||||
"assets/img/sub_menu.png",
|
||||
width: 12,
|
||||
height: 12,
|
||||
fit: BoxFit.contain,
|
||||
))
|
||||
],
|
||||
));
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class NotificationRow extends StatelessWidget {
|
||||
final Map nObj;
|
||||
const NotificationRow({super.key, required this.nObj});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
child: SvgPicture.asset(
|
||||
nObj["image"].toString(),
|
||||
width: 40,
|
||||
height: 40
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 15,
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
nObj["title"].toString(),
|
||||
style: TextStyle(
|
||||
color: TColor.black,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 12),
|
||||
),
|
||||
Text(
|
||||
nObj["time"].toString(),
|
||||
style: TextStyle(
|
||||
color: TColor.gray,
|
||||
fontSize: 10,
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
IconButton(
|
||||
onPressed: () {},
|
||||
icon: SvgPicture.asset(
|
||||
"assets/img/sub_menu.svg",
|
||||
width: 15,
|
||||
height: 15,
|
||||
fit: BoxFit.contain,
|
||||
))
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
||||
import '../common/colo_extension.dart';
|
||||
|
||||
class OnBoardingPage extends StatelessWidget {
|
||||
final Map pObj;
|
||||
const OnBoardingPage({super.key, required this.pObj});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var media = MediaQuery.of(context).size;
|
||||
return
|
||||
|
||||
SizedBox(
|
||||
width: media.width,
|
||||
height: media.height,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
pObj["image"].toString(),
|
||||
width: media.width,
|
||||
),
|
||||
SizedBox(
|
||||
height: media.width * 0.15,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 30),
|
||||
child: Text(
|
||||
pObj["title"].toString(),
|
||||
style: TextStyle(
|
||||
color: TColor.black,
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w700),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: media.width * 0.03,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 30),
|
||||
child: Text(
|
||||
pObj["subtitle"].toString(),
|
||||
style: TextStyle(color: TColor.gray, fontSize: 14),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../common/colo_extension.dart';
|
||||
|
||||
enum RoundButtonType { bgGradient, bgSGradient , textGradient }
|
||||
|
||||
class RoundButton extends StatelessWidget {
|
||||
final String title;
|
||||
final RoundButtonType type;
|
||||
final VoidCallback onPressed;
|
||||
final double fontSize;
|
||||
final double elevation;
|
||||
final FontWeight fontWeight;
|
||||
|
||||
const RoundButton(
|
||||
{super.key,
|
||||
required this.title,
|
||||
this.type = RoundButtonType.bgGradient,
|
||||
this.fontSize = 16,
|
||||
this.elevation = 1,
|
||||
this.fontWeight=FontWeight.w700,
|
||||
required this.onPressed});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: type == RoundButtonType.bgSGradient ? TColor.secondaryG : TColor.primaryG,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(25),
|
||||
boxShadow: type == RoundButtonType.bgGradient || type == RoundButtonType.bgSGradient
|
||||
? const [
|
||||
BoxShadow(
|
||||
color: Colors.black26,
|
||||
blurRadius: 0.5,
|
||||
offset: Offset(0, 0.5))
|
||||
]
|
||||
: null),
|
||||
child: MaterialButton(
|
||||
onPressed: onPressed,
|
||||
height: 50,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(25)),
|
||||
textColor: TColor.primaryColor1,
|
||||
minWidth: double.maxFinite,
|
||||
elevation: type == RoundButtonType.bgGradient || type == RoundButtonType.bgSGradient ? 0 : elevation,
|
||||
color: type == RoundButtonType.bgGradient || type == RoundButtonType.bgSGradient
|
||||
? Colors.transparent
|
||||
: TColor.white,
|
||||
child: type == RoundButtonType.bgGradient || type == RoundButtonType.bgSGradient
|
||||
? Text(title,
|
||||
style: TextStyle(
|
||||
color: TColor.white,
|
||||
fontSize: fontSize,
|
||||
fontWeight: fontWeight))
|
||||
: 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(title,
|
||||
style: TextStyle(
|
||||
color: TColor.primaryColor1,
|
||||
fontSize: fontSize,
|
||||
fontWeight: fontWeight)),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
||||
import '../common/colo_extension.dart';
|
||||
|
||||
class RoundTextField extends StatelessWidget {
|
||||
final TextEditingController? controller;
|
||||
final TextInputType? keyboardType;
|
||||
final String hitText;
|
||||
final String icon;
|
||||
final Widget? rigtIcon;
|
||||
final bool obscureText;
|
||||
final EdgeInsets? margin;
|
||||
const RoundTextField({super.key, required this.hitText, required this.icon, this.controller, this.margin, this.keyboardType, this.obscureText = false , this.rigtIcon });
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
margin: margin,
|
||||
decoration: BoxDecoration(
|
||||
color: TColor.lightGray, borderRadius: BorderRadius.circular(15)),
|
||||
child: TextField(
|
||||
controller: controller,
|
||||
keyboardType: keyboardType,
|
||||
obscureText: obscureText,
|
||||
decoration: InputDecoration(
|
||||
contentPadding:
|
||||
const EdgeInsets.symmetric(vertical: 15, horizontal: 15),
|
||||
enabledBorder: InputBorder.none,
|
||||
focusedBorder: InputBorder.none,
|
||||
hintText: hitText,
|
||||
suffixIcon: rigtIcon,
|
||||
prefixIcon: Container(
|
||||
alignment: Alignment.center,
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: SvgPicture.asset(
|
||||
icon,
|
||||
width: 20,
|
||||
height: 20,
|
||||
fit: BoxFit.contain,
|
||||
)),
|
||||
hintStyle: TextStyle(color: TColor.gray, fontSize: 12)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../common/colo_extension.dart';
|
||||
|
||||
class SettingRow extends StatelessWidget {
|
||||
final String icon;
|
||||
final String title;
|
||||
final VoidCallback onPressed;
|
||||
const SettingRow({super.key, required this.icon, required this.title, required this.onPressed });
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: onPressed,
|
||||
child: SizedBox(
|
||||
height: 30,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Image.asset(icon,
|
||||
height: 15, width: 15, fit: BoxFit.contain),
|
||||
const SizedBox(
|
||||
width: 15,
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
color: TColor.black,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
),
|
||||
Image.asset("assets/img/p_next.png",
|
||||
height: 12, width: 12, fit: BoxFit.contain)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,197 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
||||
|
||||
class Stats extends StatelessWidget {
|
||||
const Stats({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 30),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
'Statistiques',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Icon(
|
||||
Icons.pie_chart_rounded,
|
||||
size: 15,
|
||||
color: TColor.secondaryColor1,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
children: const [
|
||||
SizedBox(width: 30),
|
||||
InfoStat(
|
||||
icon: Icons.timer,
|
||||
iconColor: Color.fromARGB(255, 255, 255, 255),
|
||||
iconBackground: Color(0xff6131AD),
|
||||
time: '+5s',
|
||||
label: 'Time',
|
||||
value: '30:34',
|
||||
),
|
||||
SizedBox(width: 15),
|
||||
InfoStat(
|
||||
icon: Icons.favorite_outline,
|
||||
iconColor: Color.fromARGB(255, 255, 255, 255),
|
||||
iconBackground: Color(0xff6131AD),
|
||||
time: '+5s',
|
||||
label: 'Heart Rate',
|
||||
value: '151bpm',
|
||||
),
|
||||
SizedBox(width: 15),
|
||||
InfoStat(
|
||||
icon: Icons.bolt,
|
||||
iconColor: Color.fromARGB(255, 255, 255, 255),
|
||||
iconBackground: Color(0xff6131AD),
|
||||
time: '+5s',
|
||||
label: 'Energy',
|
||||
value: '169kcal',
|
||||
),
|
||||
SizedBox(width: 30),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class InfoStat extends StatelessWidget {
|
||||
final IconData icon;
|
||||
final Color iconColor;
|
||||
final Color iconBackground;
|
||||
final String time;
|
||||
final String label;
|
||||
final String value;
|
||||
|
||||
const InfoStat({
|
||||
Key? key,
|
||||
required this.icon,
|
||||
required this.iconColor,
|
||||
required this.iconBackground,
|
||||
required this.time,
|
||||
required this.label,
|
||||
required this.value,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: 110,
|
||||
width: 110,
|
||||
padding: const EdgeInsets.all(8),
|
||||
margin: const EdgeInsets.symmetric(vertical: 5),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
border: Border.all(
|
||||
color: const Color(0xffe1e1e1),
|
||||
),
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: Colors.black12,
|
||||
offset: Offset(3, 3),
|
||||
blurRadius: 3,
|
||||
),
|
||||
]),
|
||||
child: Stack(
|
||||
children: [
|
||||
StatIcon(
|
||||
icon: icon,
|
||||
iconColor: iconColor,
|
||||
iconBackground: iconBackground,
|
||||
),
|
||||
Change(time: time),
|
||||
Align(
|
||||
alignment: Alignment.bottomLeft,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(fontSize: 10),
|
||||
),
|
||||
Text(
|
||||
value,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Change extends StatelessWidget {
|
||||
const Change({
|
||||
Key? key,
|
||||
required this.time,
|
||||
}) : super(key: key);
|
||||
|
||||
final String time;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Align(
|
||||
alignment: Alignment.topRight,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 1,
|
||||
horizontal: 4,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.green,
|
||||
borderRadius: BorderRadius.circular(500),
|
||||
),
|
||||
child: Text(
|
||||
time,
|
||||
style: const TextStyle(fontSize: 10, color: Colors.white),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class StatIcon extends StatelessWidget {
|
||||
const StatIcon({
|
||||
Key? key,
|
||||
required this.icon,
|
||||
required this.iconColor,
|
||||
required this.iconBackground,
|
||||
}) : super(key: key);
|
||||
|
||||
final IconData icon;
|
||||
final Color iconColor;
|
||||
final Color iconBackground;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(5),
|
||||
decoration: BoxDecoration(
|
||||
color: iconBackground,
|
||||
borderRadius: BorderRadius.circular(9),
|
||||
),
|
||||
child: Icon(icon, size: 15, color: iconColor),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
import 'package:smartfit_app_mobile/common_widget/helpers.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class Steps extends StatelessWidget {
|
||||
const Steps({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String steps = formatNumber(randBetween(3000, 6000));
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 20),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
steps,
|
||||
style: const TextStyle(
|
||||
fontSize: 33,
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
),
|
||||
const Text(
|
||||
'Total Steps',
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 2,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class TabButton extends StatelessWidget {
|
||||
final String icon;
|
||||
final String selectIcon;
|
||||
final VoidCallback onTap;
|
||||
final bool isActive;
|
||||
const TabButton(
|
||||
{super.key,
|
||||
required this.icon,
|
||||
required this.selectIcon,
|
||||
required this.isActive,
|
||||
required this.onTap});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||
SvgPicture.asset(isActive ? selectIcon : icon,
|
||||
width: 28, height: 28, fit: BoxFit.fitWidth),
|
||||
SizedBox(
|
||||
height: isActive ? 12: 8,
|
||||
),
|
||||
if(isActive)
|
||||
Container(
|
||||
width: 4,
|
||||
height: 4,
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: TColor.secondaryG,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(2)),
|
||||
)
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../common/colo_extension.dart';
|
||||
|
||||
class TitleSubtitleCell extends StatelessWidget {
|
||||
final String title;
|
||||
final String subtitle;
|
||||
const TitleSubtitleCell({super.key, required this.title, required this.subtitle});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: TColor.white,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
boxShadow: const [BoxShadow(color: Colors.black12, blurRadius: 2)]),
|
||||
child: Column(
|
||||
children: [
|
||||
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(
|
||||
title,
|
||||
style: TextStyle(
|
||||
color: TColor.white.withOpacity(0.7),
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 14),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
subtitle,
|
||||
style: TextStyle(
|
||||
color: TColor.gray,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class TodayTargetCell extends StatelessWidget {
|
||||
final String icon;
|
||||
final String value;
|
||||
final String title;
|
||||
const TodayTargetCell({super.key, required this.icon, required this.value, required this.title});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: 70,
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: TColor.white,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
icon,
|
||||
width: 40,
|
||||
height: 40,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 8,
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
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(
|
||||
value,
|
||||
style: TextStyle(
|
||||
color: TColor.white.withOpacity(0.7),
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 14),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
color: TColor.black,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
))
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1 +1,2 @@
|
||||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||
#include "ephemeral/Flutter-Generated.xcconfig"
|
||||
|
@ -1 +1,2 @@
|
||||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||
#include "ephemeral/Flutter-Generated.xcconfig"
|
||||
|
@ -0,0 +1,43 @@
|
||||
platform :osx, '10.14'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
||||
project 'Runner', {
|
||||
'Debug' => :debug,
|
||||
'Profile' => :release,
|
||||
'Release' => :release,
|
||||
}
|
||||
|
||||
def flutter_root
|
||||
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)
|
||||
unless File.exist?(generated_xcode_build_settings_path)
|
||||
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first"
|
||||
end
|
||||
|
||||
File.foreach(generated_xcode_build_settings_path) do |line|
|
||||
matches = line.match(/FLUTTER_ROOT\=(.*)/)
|
||||
return matches[1].strip if matches
|
||||
end
|
||||
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\""
|
||||
end
|
||||
|
||||
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
|
||||
|
||||
flutter_macos_podfile_setup
|
||||
|
||||
target 'Runner' do
|
||||
use_frameworks!
|
||||
use_modular_headers!
|
||||
|
||||
flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))
|
||||
target 'RunnerTests' do
|
||||
inherit! :search_paths
|
||||
end
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
flutter_additional_macos_build_settings(target)
|
||||
end
|
||||
end
|