forked from eatvio/eatvio_app
user details created
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import 'package:badges/badges.dart' as badges;
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/utils/image_constant.dart';
|
||||
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/new_messages_cubit/new_messages_cubit.dart';
|
||||
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/new_messages_cubit/new_messages_state.dart';
|
||||
@@ -6,6 +7,8 @@ import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/noti
|
||||
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_state.dart';
|
||||
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_cubit.dart';
|
||||
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_state.dart';
|
||||
import 'package:eatvio_app/features/profile/repositories/profile_repository.dart';
|
||||
import 'package:eatvio_app/features/user_details/presentation/user_details_screen.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -28,7 +31,7 @@ class BottomNavigationBarWidget extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _BottomNavigationBarWidgetState extends State<BottomNavigationBarWidget> {
|
||||
void _onItemTapped(int index) {
|
||||
void _onItemTapped(int index) async {
|
||||
if (currentBottomNavBarIndex != index) {
|
||||
setState(() {
|
||||
currentBottomNavBarIndex = index;
|
||||
|
||||
@@ -12,9 +12,12 @@ class ChatSelectCubit extends Cubit<ChatSelectState> {
|
||||
getChatRooms({String? query}) async {
|
||||
emit(ChatSelectState.loading());
|
||||
try {
|
||||
emit(ChatSelectState.loaded(
|
||||
chatRooms: (await chatRepository.getChatRoomPreviews(query: query)),
|
||||
),);
|
||||
final chatRooms = await chatRepository.getChatRoomPreviews(query: query);
|
||||
emit(
|
||||
ChatSelectState.loaded(
|
||||
chatRooms: chatRooms,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
emit(
|
||||
ChatSelectState.error(errorMessage: e.toString()),
|
||||
|
||||
@@ -190,7 +190,10 @@ class _DietPreviewScreenState extends State<DietPreviewScreen> {
|
||||
actions: [
|
||||
PortalTarget(
|
||||
visible: isMoreOptionsVisible,
|
||||
portalFollower: MoreOptions(disableActions: true, id: widget.diet.id),
|
||||
portalFollower: MoreOptions(
|
||||
disableActions: true,
|
||||
path: 'diet/${widget.diet.id}',
|
||||
),
|
||||
anchor: Aligned(
|
||||
shiftToWithinBound: AxisFlag(x: true, y: true),
|
||||
follower: Alignment.topRight,
|
||||
|
||||
@@ -151,7 +151,7 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
|
||||
BookmarkButton(
|
||||
isFavorite: dietState.diet.isFavorite,
|
||||
onTap: () {
|
||||
if (dietState.diet.isFavorite) {
|
||||
if (dietState.diet.isFavorite) {
|
||||
dietsCubit.removeFromFavorite(widget.diet.id, widget.index);
|
||||
} else {
|
||||
dietsCubit.addToFavorite(widget.diet.id, widget.index);
|
||||
@@ -291,7 +291,9 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
|
||||
actions: [
|
||||
PortalTarget(
|
||||
visible: isMoreOptionsVisible,
|
||||
portalFollower: MoreOptions(id: widget.diet.id),
|
||||
portalFollower: MoreOptions(
|
||||
path: 'diet/${widget.diet.id}',
|
||||
),
|
||||
anchor: Aligned(
|
||||
shiftToWithinBound: AxisFlag(x: true, y: true),
|
||||
follower: Alignment.topRight,
|
||||
|
||||
@@ -12,8 +12,8 @@ import 'package:go_router/go_router.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
|
||||
class MoreOptions extends StatelessWidget {
|
||||
const MoreOptions({super.key, required this.id, this.disableActions});
|
||||
final int id;
|
||||
const MoreOptions({super.key, this.disableActions, required this.path});
|
||||
final String path;
|
||||
final bool? disableActions;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -26,10 +26,12 @@ class MoreOptions extends StatelessWidget {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap:disableActions == true ? null : () {
|
||||
Clipboard.setData(ClipboardData(text: baseUrl + '/ru/diet/' + id.toString()));
|
||||
showInfoToast(s.link_was_copied);
|
||||
},
|
||||
onTap: disableActions == true
|
||||
? null
|
||||
: () {
|
||||
Clipboard.setData(ClipboardData(text: '$baseUrl/ru/$path'));
|
||||
showInfoToast(s.link_was_copied);
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
@@ -48,11 +50,13 @@ class MoreOptions extends StatelessWidget {
|
||||
child: CustomDivider(),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: disableActions == true ? null : () => Share.shareUri(
|
||||
Uri.parse(
|
||||
baseUrl + '/ru/diet/' + id.toString(),
|
||||
),
|
||||
),
|
||||
onTap: disableActions == true
|
||||
? null
|
||||
: () => Share.shareUri(
|
||||
Uri.parse(
|
||||
'$baseUrl/ru/$path',
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
@@ -71,9 +75,11 @@ class MoreOptions extends StatelessWidget {
|
||||
child: CustomDivider(),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: disableActions == true ? null : () {
|
||||
context.push('complainingScreen');
|
||||
},
|
||||
onTap: disableActions == true
|
||||
? null
|
||||
: () {
|
||||
context.push('complainingScreen');
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
|
||||
@@ -292,7 +292,9 @@ class _AboutPlanScreenState extends State<AboutPlanScreen> {
|
||||
actions: [
|
||||
PortalTarget(
|
||||
visible: isMoreOptionsVisible,
|
||||
portalFollower: MoreOptions(id: widget.plan.id),
|
||||
portalFollower: MoreOptions(
|
||||
path: 'plan/${widget.plan.id}',
|
||||
),
|
||||
anchor: Aligned(
|
||||
shiftToWithinBound: AxisFlag(x: true, y: true),
|
||||
follower: Alignment.topRight,
|
||||
|
||||
@@ -276,7 +276,10 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
height: 378,
|
||||
child: PageView.builder(
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return PlanWidget(plan: state.plansList[index], index: index,);
|
||||
return PlanWidget(
|
||||
plan: state.plansList[index],
|
||||
index: index,
|
||||
);
|
||||
},
|
||||
onPageChanged: (bullet) {
|
||||
setState(() {
|
||||
@@ -1097,7 +1100,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
_charts() {
|
||||
_charts() {
|
||||
return Material(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
|
||||
@@ -8,12 +8,12 @@ import 'package:syncfusion_flutter_charts/charts.dart';
|
||||
|
||||
class CircumferenceChartWidget extends StatefulWidget {
|
||||
final List<CircumferenceModel> circumferencePoints;
|
||||
final ProfileCubit profileCubit;
|
||||
final ProfileCubit? profileCubit;
|
||||
|
||||
const CircumferenceChartWidget({
|
||||
super.key,
|
||||
required this.circumferencePoints,
|
||||
required this.profileCubit,
|
||||
this.profileCubit,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -171,117 +171,118 @@ class _CircumferenceChartWidgetState extends State<CircumferenceChartWidget> {
|
||||
series: _getSplineSeries(),
|
||||
tooltipBehavior: TooltipBehavior(enable: true),
|
||||
),
|
||||
FloatingActionButton.small(
|
||||
heroTag: 'addCircumference',
|
||||
onPressed: () {
|
||||
if (widget.circumferencePoints.isNotEmpty) {
|
||||
chest = widget.circumferencePoints.last.chestCircumference;
|
||||
waist = widget.circumferencePoints.last.waistCircumference;
|
||||
hip = widget.circumferencePoints.last.hipCircumference;
|
||||
chestController = FixedExtentScrollController(initialItem: chest - 20);
|
||||
waistController = FixedExtentScrollController(initialItem: waist - 20);
|
||||
hipController = FixedExtentScrollController(initialItem: hip - 20);
|
||||
} else {
|
||||
chestController = FixedExtentScrollController();
|
||||
waistController = FixedExtentScrollController();
|
||||
hipController = FixedExtentScrollController();
|
||||
}
|
||||
showModalBottomSheet(
|
||||
useRootNavigator: true,
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CupertinoPicker(
|
||||
magnification: 1.22,
|
||||
squeeze: 1.2,
|
||||
useMagnifier: true,
|
||||
scrollController: chestController,
|
||||
itemExtent: 24,
|
||||
onSelectedItemChanged: (int value) {
|
||||
chest = value;
|
||||
},
|
||||
children: [
|
||||
for (int i = 20; i < 200; i++) Text('$i'),
|
||||
],
|
||||
if (widget.profileCubit != null)
|
||||
FloatingActionButton.small(
|
||||
heroTag: 'addCircumference',
|
||||
onPressed: () {
|
||||
if (widget.circumferencePoints.isNotEmpty) {
|
||||
chest = widget.circumferencePoints.last.chestCircumference;
|
||||
waist = widget.circumferencePoints.last.waistCircumference;
|
||||
hip = widget.circumferencePoints.last.hipCircumference;
|
||||
chestController = FixedExtentScrollController(initialItem: chest - 20);
|
||||
waistController = FixedExtentScrollController(initialItem: waist - 20);
|
||||
hipController = FixedExtentScrollController(initialItem: hip - 20);
|
||||
} else {
|
||||
chestController = FixedExtentScrollController();
|
||||
waistController = FixedExtentScrollController();
|
||||
hipController = FixedExtentScrollController();
|
||||
}
|
||||
showModalBottomSheet(
|
||||
useRootNavigator: true,
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CupertinoPicker(
|
||||
magnification: 1.22,
|
||||
squeeze: 1.2,
|
||||
useMagnifier: true,
|
||||
scrollController: chestController,
|
||||
itemExtent: 24,
|
||||
onSelectedItemChanged: (int value) {
|
||||
chest = value;
|
||||
},
|
||||
children: [
|
||||
for (int i = 20; i < 200; i++) Text('$i'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: CupertinoPicker(
|
||||
magnification: 1.22,
|
||||
squeeze: 1.2,
|
||||
useMagnifier: true,
|
||||
scrollController: waistController,
|
||||
itemExtent: 24,
|
||||
onSelectedItemChanged: (int value) {
|
||||
waist = value;
|
||||
},
|
||||
children: [
|
||||
for (int i = 20; i < 200; i++) Text('$i'),
|
||||
],
|
||||
Expanded(
|
||||
child: CupertinoPicker(
|
||||
magnification: 1.22,
|
||||
squeeze: 1.2,
|
||||
useMagnifier: true,
|
||||
scrollController: waistController,
|
||||
itemExtent: 24,
|
||||
onSelectedItemChanged: (int value) {
|
||||
waist = value;
|
||||
},
|
||||
children: [
|
||||
for (int i = 20; i < 200; i++) Text('$i'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: CupertinoPicker(
|
||||
magnification: 1.22,
|
||||
squeeze: 1.2,
|
||||
useMagnifier: true,
|
||||
scrollController: hipController,
|
||||
itemExtent: 24,
|
||||
onSelectedItemChanged: (int value) {
|
||||
hip = value;
|
||||
},
|
||||
children: [
|
||||
for (int i = 20; i < 200; i++) Text('$i'),
|
||||
],
|
||||
Expanded(
|
||||
child: CupertinoPicker(
|
||||
magnification: 1.22,
|
||||
squeeze: 1.2,
|
||||
useMagnifier: true,
|
||||
scrollController: hipController,
|
||||
itemExtent: 24,
|
||||
onSelectedItemChanged: (int value) {
|
||||
hip = value;
|
||||
},
|
||||
children: [
|
||||
for (int i = 20; i < 200; i++) Text('$i'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
widget.profileCubit.addCircumference(
|
||||
chestCircumference: chest + 20,
|
||||
waistCircumference: waist + 20,
|
||||
hipCircumference: hip + 20,
|
||||
);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: Ink(
|
||||
width: MediaQuery.of(context).size.width - 32,
|
||||
padding: EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.blueA400,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
],
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Сохранить',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
widget.profileCubit?.addCircumference(
|
||||
chestCircumference: chest + 20,
|
||||
waistCircumference: waist + 20,
|
||||
hipCircumference: hip + 20,
|
||||
);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: Ink(
|
||||
width: MediaQuery.of(context).size.width - 32,
|
||||
padding: EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.blueA400,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Сохранить',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
backgroundColor: appTheme.blueA400,
|
||||
shape: CircleBorder(),
|
||||
child: Icon(
|
||||
Icons.add,
|
||||
color: Colors.white,
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
backgroundColor: appTheme.blueA400,
|
||||
shape: CircleBorder(),
|
||||
child: Icon(
|
||||
Icons.add,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
||||
@@ -8,12 +8,12 @@ import 'package:syncfusion_flutter_charts/charts.dart';
|
||||
|
||||
class WeightChartWidget extends StatefulWidget {
|
||||
final List<WeightModel> weightPoints;
|
||||
final ProfileCubit profileCubit;
|
||||
final ProfileCubit? profileCubit;
|
||||
|
||||
const WeightChartWidget({
|
||||
super.key,
|
||||
required this.weightPoints,
|
||||
required this.profileCubit,
|
||||
this.profileCubit,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -111,99 +111,100 @@ class _WeightChartWidgetState extends State<WeightChartWidget> {
|
||||
series: _getSplineSeries(),
|
||||
tooltipBehavior: TooltipBehavior(enable: true),
|
||||
),
|
||||
FloatingActionButton.small(
|
||||
heroTag: 'addWeight',
|
||||
onPressed: () {
|
||||
if (widget.weightPoints.isNotEmpty) {
|
||||
try {
|
||||
weightKilo = int.parse(widget.weightPoints.last.weight.toString().split('.')[0]);
|
||||
weightGrams = int.parse(widget.weightPoints.last.weight.toString().split('.')[1][0]);
|
||||
} catch (e) {
|
||||
weightGrams = 0;
|
||||
if (widget.profileCubit != null)
|
||||
FloatingActionButton.small(
|
||||
heroTag: 'addWeight',
|
||||
onPressed: () {
|
||||
if (widget.weightPoints.isNotEmpty) {
|
||||
try {
|
||||
weightKilo = int.parse(widget.weightPoints.last.weight.toString().split('.')[0]);
|
||||
weightGrams = int.parse(widget.weightPoints.last.weight.toString().split('.')[1][0]);
|
||||
} catch (e) {
|
||||
weightGrams = 0;
|
||||
}
|
||||
weightKiloController = FixedExtentScrollController(initialItem: weightKilo - 20);
|
||||
weightGramsController = FixedExtentScrollController(initialItem: weightGrams);
|
||||
} else {
|
||||
weightKiloController = FixedExtentScrollController();
|
||||
weightGramsController = FixedExtentScrollController();
|
||||
}
|
||||
weightKiloController = FixedExtentScrollController(initialItem: weightKilo - 20);
|
||||
weightGramsController = FixedExtentScrollController(initialItem: weightGrams);
|
||||
} else {
|
||||
weightKiloController = FixedExtentScrollController();
|
||||
weightGramsController = FixedExtentScrollController();
|
||||
}
|
||||
showModalBottomSheet(
|
||||
useRootNavigator: true,
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CupertinoPicker(
|
||||
magnification: 1.22,
|
||||
squeeze: 1.2,
|
||||
useMagnifier: true,
|
||||
scrollController: weightKiloController,
|
||||
itemExtent: 24,
|
||||
onSelectedItemChanged: (int value) {
|
||||
weightKilo = value + 20;
|
||||
},
|
||||
children: [
|
||||
for (int i = 20; i < 300; i++) Text('$i'),
|
||||
],
|
||||
showModalBottomSheet(
|
||||
useRootNavigator: true,
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CupertinoPicker(
|
||||
magnification: 1.22,
|
||||
squeeze: 1.2,
|
||||
useMagnifier: true,
|
||||
scrollController: weightKiloController,
|
||||
itemExtent: 24,
|
||||
onSelectedItemChanged: (int value) {
|
||||
weightKilo = value + 20;
|
||||
},
|
||||
children: [
|
||||
for (int i = 20; i < 300; i++) Text('$i'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: CupertinoPicker(
|
||||
magnification: 1.22,
|
||||
squeeze: 1.2,
|
||||
useMagnifier: true,
|
||||
scrollController: weightGramsController,
|
||||
itemExtent: 24,
|
||||
onSelectedItemChanged: (int value) {
|
||||
weightGrams = value;
|
||||
},
|
||||
children: [
|
||||
for (int i = 0; i < 10; i++) Text('$i'),
|
||||
],
|
||||
Expanded(
|
||||
child: CupertinoPicker(
|
||||
magnification: 1.22,
|
||||
squeeze: 1.2,
|
||||
useMagnifier: true,
|
||||
scrollController: weightGramsController,
|
||||
itemExtent: 24,
|
||||
onSelectedItemChanged: (int value) {
|
||||
weightGrams = value;
|
||||
},
|
||||
children: [
|
||||
for (int i = 0; i < 10; i++) Text('$i'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
widget.profileCubit.addWeight(weight: double.parse('$weightKilo.$weightGrams'));
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: Ink(
|
||||
width: MediaQuery.of(context).size.width - 32,
|
||||
padding: EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.blueA400,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
],
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Сохранить',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
widget.profileCubit?.addWeight(weight: double.parse('$weightKilo.$weightGrams'));
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: Ink(
|
||||
width: MediaQuery.of(context).size.width - 32,
|
||||
padding: EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.blueA400,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Сохранить',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
backgroundColor: appTheme.blueA400,
|
||||
shape: CircleBorder(),
|
||||
child: Icon(
|
||||
Icons.add,
|
||||
color: Colors.white,
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
backgroundColor: appTheme.blueA400,
|
||||
shape: CircleBorder(),
|
||||
child: Icon(
|
||||
Icons.add,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:eatvio_app/features/profile/repositories/profile_repository.dart';
|
||||
import 'package:eatvio_app/features/user_details/presentation/cubit/user_details_state.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class UserDetailsCubit extends Cubit<UserDetailsState> {
|
||||
final ProfileRepository profileRepository;
|
||||
|
||||
UserDetailsCubit({required this.profileRepository}) : super(UserDetailsState());
|
||||
|
||||
void getUserDetails(String slug) async {
|
||||
try {
|
||||
final profileDetails = await profileRepository.getProfileDetailsBySlug(slug);
|
||||
emit(state.copyWith(profileDetails: profileDetails, isLoading: false));
|
||||
getChartData(slug: slug);
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
emit(state.copyWith(error: e.toString(), isLoading: false));
|
||||
}
|
||||
}
|
||||
|
||||
void getChartData({
|
||||
String period = '1',
|
||||
required String slug,
|
||||
}) async {
|
||||
try {
|
||||
final weightPoints = await profileRepository.getWeight(period: period);
|
||||
final circumferencePoints = await profileRepository.getCircumferences(period: period);
|
||||
emit(
|
||||
state.copyWith(
|
||||
weightPoints: weightPoints,
|
||||
circumferencePoints: circumferencePoints,
|
||||
),
|
||||
);
|
||||
} catch (e, stackTrace) {
|
||||
log(e.toString(), stackTrace: stackTrace);
|
||||
emit(state.copyWith(error: e.toString(), isLoading: false));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import 'package:eatvio_app/features/profile/models/circumference_model.dart';
|
||||
import 'package:eatvio_app/features/profile/models/profile_model.dart';
|
||||
import 'package:eatvio_app/features/profile/models/weight_model.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'user_details_state.freezed.dart';
|
||||
|
||||
@freezed
|
||||
class UserDetailsState with _$UserDetailsState {
|
||||
factory UserDetailsState({
|
||||
@Default(false) bool isLoading,
|
||||
String? error,
|
||||
ProfileDetailsModel? profileDetails,
|
||||
List<WeightModel>? weightPoints,
|
||||
List<CircumferenceModel>? circumferencePoints,
|
||||
}) = _UserDetailsState;
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'user_details_state.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
/// @nodoc
|
||||
mixin _$UserDetailsState {
|
||||
bool get isLoading => throw _privateConstructorUsedError;
|
||||
String? get error => throw _privateConstructorUsedError;
|
||||
ProfileDetailsModel? get profileDetails => throw _privateConstructorUsedError;
|
||||
List<WeightModel>? get weightPoints => throw _privateConstructorUsedError;
|
||||
List<CircumferenceModel>? get circumferencePoints =>
|
||||
throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of UserDetailsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$UserDetailsStateCopyWith<UserDetailsState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $UserDetailsStateCopyWith<$Res> {
|
||||
factory $UserDetailsStateCopyWith(
|
||||
UserDetailsState value, $Res Function(UserDetailsState) then) =
|
||||
_$UserDetailsStateCopyWithImpl<$Res, UserDetailsState>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{bool isLoading,
|
||||
String? error,
|
||||
ProfileDetailsModel? profileDetails,
|
||||
List<WeightModel>? weightPoints,
|
||||
List<CircumferenceModel>? circumferencePoints});
|
||||
|
||||
$ProfileDetailsModelCopyWith<$Res>? get profileDetails;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$UserDetailsStateCopyWithImpl<$Res, $Val extends UserDetailsState>
|
||||
implements $UserDetailsStateCopyWith<$Res> {
|
||||
_$UserDetailsStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of UserDetailsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? isLoading = null,
|
||||
Object? error = freezed,
|
||||
Object? profileDetails = freezed,
|
||||
Object? weightPoints = freezed,
|
||||
Object? circumferencePoints = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
isLoading: null == isLoading
|
||||
? _value.isLoading
|
||||
: isLoading // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
error: freezed == error
|
||||
? _value.error
|
||||
: error // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
profileDetails: freezed == profileDetails
|
||||
? _value.profileDetails
|
||||
: profileDetails // ignore: cast_nullable_to_non_nullable
|
||||
as ProfileDetailsModel?,
|
||||
weightPoints: freezed == weightPoints
|
||||
? _value.weightPoints
|
||||
: weightPoints // ignore: cast_nullable_to_non_nullable
|
||||
as List<WeightModel>?,
|
||||
circumferencePoints: freezed == circumferencePoints
|
||||
? _value.circumferencePoints
|
||||
: circumferencePoints // ignore: cast_nullable_to_non_nullable
|
||||
as List<CircumferenceModel>?,
|
||||
) as $Val);
|
||||
}
|
||||
|
||||
/// Create a copy of UserDetailsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$ProfileDetailsModelCopyWith<$Res>? get profileDetails {
|
||||
if (_value.profileDetails == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $ProfileDetailsModelCopyWith<$Res>(_value.profileDetails!, (value) {
|
||||
return _then(_value.copyWith(profileDetails: value) as $Val);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$UserDetailsStateImplCopyWith<$Res>
|
||||
implements $UserDetailsStateCopyWith<$Res> {
|
||||
factory _$$UserDetailsStateImplCopyWith(_$UserDetailsStateImpl value,
|
||||
$Res Function(_$UserDetailsStateImpl) then) =
|
||||
__$$UserDetailsStateImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{bool isLoading,
|
||||
String? error,
|
||||
ProfileDetailsModel? profileDetails,
|
||||
List<WeightModel>? weightPoints,
|
||||
List<CircumferenceModel>? circumferencePoints});
|
||||
|
||||
@override
|
||||
$ProfileDetailsModelCopyWith<$Res>? get profileDetails;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$UserDetailsStateImplCopyWithImpl<$Res>
|
||||
extends _$UserDetailsStateCopyWithImpl<$Res, _$UserDetailsStateImpl>
|
||||
implements _$$UserDetailsStateImplCopyWith<$Res> {
|
||||
__$$UserDetailsStateImplCopyWithImpl(_$UserDetailsStateImpl _value,
|
||||
$Res Function(_$UserDetailsStateImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of UserDetailsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? isLoading = null,
|
||||
Object? error = freezed,
|
||||
Object? profileDetails = freezed,
|
||||
Object? weightPoints = freezed,
|
||||
Object? circumferencePoints = freezed,
|
||||
}) {
|
||||
return _then(_$UserDetailsStateImpl(
|
||||
isLoading: null == isLoading
|
||||
? _value.isLoading
|
||||
: isLoading // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
error: freezed == error
|
||||
? _value.error
|
||||
: error // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
profileDetails: freezed == profileDetails
|
||||
? _value.profileDetails
|
||||
: profileDetails // ignore: cast_nullable_to_non_nullable
|
||||
as ProfileDetailsModel?,
|
||||
weightPoints: freezed == weightPoints
|
||||
? _value._weightPoints
|
||||
: weightPoints // ignore: cast_nullable_to_non_nullable
|
||||
as List<WeightModel>?,
|
||||
circumferencePoints: freezed == circumferencePoints
|
||||
? _value._circumferencePoints
|
||||
: circumferencePoints // ignore: cast_nullable_to_non_nullable
|
||||
as List<CircumferenceModel>?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$UserDetailsStateImpl implements _UserDetailsState {
|
||||
_$UserDetailsStateImpl(
|
||||
{this.isLoading = false,
|
||||
this.error,
|
||||
this.profileDetails,
|
||||
final List<WeightModel>? weightPoints,
|
||||
final List<CircumferenceModel>? circumferencePoints})
|
||||
: _weightPoints = weightPoints,
|
||||
_circumferencePoints = circumferencePoints;
|
||||
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool isLoading;
|
||||
@override
|
||||
final String? error;
|
||||
@override
|
||||
final ProfileDetailsModel? profileDetails;
|
||||
final List<WeightModel>? _weightPoints;
|
||||
@override
|
||||
List<WeightModel>? get weightPoints {
|
||||
final value = _weightPoints;
|
||||
if (value == null) return null;
|
||||
if (_weightPoints is EqualUnmodifiableListView) return _weightPoints;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(value);
|
||||
}
|
||||
|
||||
final List<CircumferenceModel>? _circumferencePoints;
|
||||
@override
|
||||
List<CircumferenceModel>? get circumferencePoints {
|
||||
final value = _circumferencePoints;
|
||||
if (value == null) return null;
|
||||
if (_circumferencePoints is EqualUnmodifiableListView)
|
||||
return _circumferencePoints;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(value);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UserDetailsState(isLoading: $isLoading, error: $error, profileDetails: $profileDetails, weightPoints: $weightPoints, circumferencePoints: $circumferencePoints)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$UserDetailsStateImpl &&
|
||||
(identical(other.isLoading, isLoading) ||
|
||||
other.isLoading == isLoading) &&
|
||||
(identical(other.error, error) || other.error == error) &&
|
||||
(identical(other.profileDetails, profileDetails) ||
|
||||
other.profileDetails == profileDetails) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._weightPoints, _weightPoints) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._circumferencePoints, _circumferencePoints));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
isLoading,
|
||||
error,
|
||||
profileDetails,
|
||||
const DeepCollectionEquality().hash(_weightPoints),
|
||||
const DeepCollectionEquality().hash(_circumferencePoints));
|
||||
|
||||
/// Create a copy of UserDetailsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$UserDetailsStateImplCopyWith<_$UserDetailsStateImpl> get copyWith =>
|
||||
__$$UserDetailsStateImplCopyWithImpl<_$UserDetailsStateImpl>(
|
||||
this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _UserDetailsState implements UserDetailsState {
|
||||
factory _UserDetailsState(
|
||||
{final bool isLoading,
|
||||
final String? error,
|
||||
final ProfileDetailsModel? profileDetails,
|
||||
final List<WeightModel>? weightPoints,
|
||||
final List<CircumferenceModel>? circumferencePoints}) =
|
||||
_$UserDetailsStateImpl;
|
||||
|
||||
@override
|
||||
bool get isLoading;
|
||||
@override
|
||||
String? get error;
|
||||
@override
|
||||
ProfileDetailsModel? get profileDetails;
|
||||
@override
|
||||
List<WeightModel>? get weightPoints;
|
||||
@override
|
||||
List<CircumferenceModel>? get circumferencePoints;
|
||||
|
||||
/// Create a copy of UserDetailsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$UserDetailsStateImplCopyWith<_$UserDetailsStateImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
520
lib/features/user_details/presentation/user_details_screen.dart
Normal file
520
lib/features/user_details/presentation/user_details_screen.dart
Normal file
@@ -0,0 +1,520 @@
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/utils/date_time_utils.dart';
|
||||
import 'package:eatvio_app/core/utils/string_extentions.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_text_form_field.dart';
|
||||
import 'package:eatvio_app/core/widgets/loader.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/more_options.dart';
|
||||
import 'package:eatvio_app/features/profile/models/circumference_model.dart';
|
||||
import 'package:eatvio_app/features/profile/models/weight_model.dart';
|
||||
import 'package:eatvio_app/features/profile/presentation/widgets/circumference_chart_widget.dart';
|
||||
import 'package:eatvio_app/features/profile/presentation/widgets/imt_chart_widget.dart';
|
||||
import 'package:eatvio_app/features/profile/presentation/widgets/weight_chart_widget.dart';
|
||||
import 'package:eatvio_app/features/user_details/presentation/cubit/user_details_cubit.dart';
|
||||
import 'package:eatvio_app/features/user_details/presentation/cubit/user_details_state.dart';
|
||||
import 'package:eatvio_app/features/user_details/presentation/widgets/expandable_bouble.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_portal/flutter_portal.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
||||
class UserDetailsScreen extends StatelessWidget {
|
||||
final String slug;
|
||||
const UserDetailsScreen({super.key, required this.slug});
|
||||
static const name = 'userDetailsScreen';
|
||||
static const path = '/user-details-screen';
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => sl<UserDetailsCubit>()..getUserDetails(slug),
|
||||
child: UserDetailsContent(
|
||||
slug: slug,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class UserDetailsContent extends StatefulWidget {
|
||||
const UserDetailsContent({super.key, required this.slug});
|
||||
final String slug;
|
||||
@override
|
||||
State<UserDetailsContent> createState() => _UserDetailsContentState();
|
||||
}
|
||||
|
||||
class _UserDetailsContentState extends State<UserDetailsContent> {
|
||||
final List<String> chipsLabelList = ['Вес', 'Замеры', 'ИМТ'];
|
||||
final List<String> chipsIntervalLabelList = ['1М', '3М', '6М', '1Г', 'ВСЁ ВРЕМЯ'];
|
||||
final List<String> chipsIntervalList = ['1', '3', '6', '12', 'all'];
|
||||
|
||||
List<WeightModel> weightPoints = [];
|
||||
List<CircumferenceModel> circumferencePoints = [];
|
||||
int _selectedChipIndex = 0;
|
||||
int _selectedIntervalChipIndex = 0;
|
||||
bool isMoreOptionsVisible = false;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = S.of(context);
|
||||
return BlocBuilder<UserDetailsCubit, UserDetailsState>(
|
||||
builder: (context, state) {
|
||||
final profileDetails = state.profileDetails;
|
||||
if (profileDetails != null && state.isLoading == false) {
|
||||
weightPoints = state.weightPoints ?? [];
|
||||
circumferencePoints = state.circumferencePoints ?? [];
|
||||
return Scaffold(
|
||||
backgroundColor: appTheme.gray100,
|
||||
appBar: AppBar(
|
||||
centerTitle: true,
|
||||
title: Text(
|
||||
'${s.user_data} ${profileDetails.firstName} ${profileDetails.lastName}',
|
||||
maxLines: 2,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
actions: [
|
||||
PortalTarget(
|
||||
visible: isMoreOptionsVisible,
|
||||
portalFollower: MoreOptions(
|
||||
path: 'profile/${widget.slug}',
|
||||
),
|
||||
anchor: Aligned(
|
||||
shiftToWithinBound: AxisFlag(x: true, y: true),
|
||||
follower: Alignment.topRight,
|
||||
target: Alignment.bottomRight,
|
||||
),
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isMoreOptionsVisible = !isMoreOptionsVisible;
|
||||
});
|
||||
},
|
||||
icon: SvgPicture.asset(
|
||||
'assets/icons/more_button.svg',
|
||||
width: 20,
|
||||
height: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
controller: ScrollController()
|
||||
..addListener(() {
|
||||
setState(() {
|
||||
isMoreOptionsVisible = false;
|
||||
});
|
||||
}),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
spacing: 12,
|
||||
children: [
|
||||
SizedBox.shrink(),
|
||||
_charts(),
|
||||
ExpandableBouble(
|
||||
initiallyExpanded: true,
|
||||
title: s.general_info,
|
||||
children: [
|
||||
Text(
|
||||
s.date_of_birth,
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
CustomTextFormField(
|
||||
readOnly: true,
|
||||
controller: TextEditingController(text: DateTime.parse(profileDetails.birthdate).format('dd.MM.yyyy')),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text(
|
||||
s.sex,
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
CustomTextFormField(
|
||||
readOnly: true,
|
||||
controller: TextEditingController(text: profileDetails.gender.parseGender()),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
ExpandableBouble(
|
||||
title: s.physical_fitness,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
s.height,
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
CustomTextFormField(
|
||||
readOnly: true,
|
||||
controller: TextEditingController(text: profileDetails.height.toString()),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
s.weight,
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
CustomTextFormField(
|
||||
readOnly: true,
|
||||
controller: TextEditingController(text: profileDetails.weight.toStringAsFixed(0)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
s.chest_circumference,
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
CustomTextFormField(
|
||||
readOnly: true,
|
||||
controller: TextEditingController(text: profileDetails.chestCircumference.toString()),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
s.waist_circumference,
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
CustomTextFormField(
|
||||
readOnly: true,
|
||||
controller: TextEditingController(text: profileDetails.waistCircumference.toString()),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
s.hip_circumference,
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
CustomTextFormField(
|
||||
readOnly: true,
|
||||
controller: TextEditingController(text: profileDetails.hipCircumference.toString()),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
ExpandableBouble(
|
||||
title: s.pressure,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
s.upper,
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
CustomTextFormField(
|
||||
readOnly: true,
|
||||
controller: TextEditingController(text: profileDetails.bloodPressureUp.toString()),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
s.lower,
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
CustomTextFormField(
|
||||
readOnly: true,
|
||||
controller: TextEditingController(text: profileDetails.bloodPressureDown.toStringAsFixed(0)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
s.has_hypo,
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
CustomTextFormField(
|
||||
readOnly: true,
|
||||
controller: TextEditingController(text: profileDetails.hasHypo.toString()),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
s.has_hyper,
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
CustomTextFormField(
|
||||
readOnly: true,
|
||||
controller: TextEditingController(text: profileDetails.hasHyper.toString()),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
ExpandableBouble(
|
||||
title: s.other_info,
|
||||
children: [
|
||||
Text(
|
||||
s.has_alergy,
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
CustomTextFormField(
|
||||
readOnly: true,
|
||||
controller: TextEditingController(text: profileDetails.aboutAlergy),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text(
|
||||
s.takes_pills,
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
CustomTextFormField(
|
||||
readOnly: true,
|
||||
controller: TextEditingController(text: profileDetails.aboutTakingPils),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text(
|
||||
s.sport_hobbies,
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
CustomTextFormField(
|
||||
readOnly: true,
|
||||
controller: TextEditingController(text: profileDetails.aboutSportHobbies),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text(
|
||||
s.liked_groceries,
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
CustomTextFormField(
|
||||
readOnly: true,
|
||||
controller: TextEditingController(text: profileDetails.favoriteFoods),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text(
|
||||
s.not_liked_groceries,
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
CustomTextFormField(
|
||||
readOnly: true,
|
||||
controller: TextEditingController(text: profileDetails.unfavoriteFoods),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text(
|
||||
s.additional_information,
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
SizedBox(
|
||||
height: 112,
|
||||
child: CustomTextFormField(
|
||||
readOnly: true,
|
||||
maxLength: 1000,
|
||||
maxLines: null,
|
||||
minLines: null,
|
||||
expands: true,
|
||||
textAlignVertical: TextAlignVertical.top,
|
||||
controller: TextEditingController(text: profileDetails.additionalInfo),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Scaffold(
|
||||
body: Loader(),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
_charts() {
|
||||
return Material(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(height: 8),
|
||||
SingleChildScrollView(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
children: [
|
||||
_choiceChipWidget(0),
|
||||
SizedBox(width: 8),
|
||||
_choiceChipWidget(1),
|
||||
SizedBox(width: 8),
|
||||
_choiceChipWidget(2),
|
||||
],
|
||||
),
|
||||
),
|
||||
Builder(
|
||||
builder: (context) {
|
||||
switch (_selectedChipIndex) {
|
||||
case 0:
|
||||
return WeightChartWidget(
|
||||
weightPoints: weightPoints,
|
||||
);
|
||||
case 1:
|
||||
return CircumferenceChartWidget(
|
||||
circumferencePoints: circumferencePoints,
|
||||
);
|
||||
case 2:
|
||||
return ImtChartWidget(
|
||||
weightPoints: weightPoints,
|
||||
);
|
||||
default:
|
||||
return SizedBox.shrink();
|
||||
}
|
||||
},
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
SizedBox(width: 16),
|
||||
_choiceIntervalChipWidget(0),
|
||||
SizedBox(width: 8),
|
||||
_choiceIntervalChipWidget(1),
|
||||
SizedBox(width: 8),
|
||||
_choiceIntervalChipWidget(2),
|
||||
SizedBox(width: 8),
|
||||
_choiceIntervalChipWidget(3),
|
||||
SizedBox(width: 8),
|
||||
_choiceIntervalChipWidget(4),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_choiceIntervalChipWidget(int index) {
|
||||
return ChoiceChip(
|
||||
selectedColor: Colors.grey.withValues(alpha: 0.1),
|
||||
pressElevation: 0,
|
||||
showCheckmark: false,
|
||||
side: BorderSide.none,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
label: Text(chipsIntervalLabelList[index]),
|
||||
labelStyle: TextStyle(
|
||||
color: appTheme.gray600,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 12,
|
||||
),
|
||||
selected: _selectedIntervalChipIndex == index,
|
||||
onSelected: (bool selected) {
|
||||
context.read<UserDetailsCubit>().getChartData(period: chipsIntervalList[index], slug: widget.slug);
|
||||
setState(() {
|
||||
_selectedIntervalChipIndex = index;
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
_choiceChipWidget(int index) {
|
||||
return ChoiceChip(
|
||||
selectedColor: appTheme.blueA400,
|
||||
pressElevation: 0,
|
||||
showCheckmark: false,
|
||||
side: BorderSide.none,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
label: Text(chipsLabelList[index]),
|
||||
labelStyle: TextStyle(
|
||||
color: index == _selectedChipIndex ? Colors.white : appTheme.gray600,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 12,
|
||||
),
|
||||
selected: _selectedChipIndex == index,
|
||||
backgroundColor: appTheme.gray100,
|
||||
onSelected: (bool selected) {
|
||||
setState(() {
|
||||
_selectedChipIndex = index;
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/widgets/main_background_bouble.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ExpandableBouble extends StatelessWidget {
|
||||
const ExpandableBouble({super.key, required this.title, required this.children, this.initiallyExpanded = false});
|
||||
final String title;
|
||||
final List<Widget> children;
|
||||
final bool initiallyExpanded;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedSize(
|
||||
duration: Duration(seconds: 1),
|
||||
child: MainBackgroundBouble(
|
||||
child: Theme(
|
||||
data: Theme.of(context).copyWith(dividerColor: Colors.transparent),
|
||||
child: ExpansionTile(
|
||||
initiallyExpanded: initiallyExpanded,
|
||||
expandedCrossAxisAlignment: CrossAxisAlignment.start,
|
||||
expandedAlignment: Alignment.bottomLeft,
|
||||
tilePadding: EdgeInsets.symmetric(horizontal: 16),
|
||||
childrenPadding: EdgeInsets.symmetric(horizontal: 16),
|
||||
title: Text(
|
||||
title,
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
children: children,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user