Files
eatvio_app/lib/features/user_details/presentation/user_details_screen.dart
2026-11-09 15:35:10 +03:00

300 lines
15 KiB
Dart

import 'package:eatvio_app/core/enums/complained_content.dart';
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/data_error_widget.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/insights/presentation/widgets/insights_card.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> {
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) {
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}', complainedContentType: ComplainedContent.profile, slug: widget.slug),
anchor: const 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: SafeArea(
child: SingleChildScrollView(
controller: ScrollController()
..addListener(() {
if (isMoreOptionsVisible) {
setState(() {
isMoreOptionsVisible = false;
});
}
}),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
spacing: 12,
children: [
const SizedBox.shrink(),
InsightsCard(slug: widget.slug),
ExpandableBouble(
initiallyExpanded: true,
title: s.general_info,
children: [
Text(s.date_of_birth, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
const SizedBox(height: 4),
CustomTextFormField(
readOnly: true,
controller: TextEditingController(text: DateTime.parse(profileDetails.birthdate).format('dd.MM.yyyy')),
),
const SizedBox(height: 16),
Text(s.sex, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
const SizedBox(height: 4),
CustomTextFormField(readOnly: true, controller: TextEditingController(text: profileDetails.gender.parseGender())),
const 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)),
const SizedBox(height: 4),
CustomTextFormField(readOnly: true, controller: TextEditingController(text: profileDetails.height.toString())),
],
),
),
const SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(s.weight, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
const SizedBox(height: 4),
CustomTextFormField(readOnly: true, controller: TextEditingController(text: profileDetails.weight.toStringAsFixed(0))),
],
),
),
],
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(s.chest_circumference, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
const SizedBox(height: 4),
CustomTextFormField(readOnly: true, controller: TextEditingController(text: profileDetails.chestCircumference.toString())),
],
),
),
const SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(s.waist_circumference, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
const SizedBox(height: 4),
CustomTextFormField(readOnly: true, controller: TextEditingController(text: profileDetails.waistCircumference.toString())),
],
),
),
const SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(s.hip_circumference, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
const SizedBox(height: 4),
CustomTextFormField(readOnly: true, controller: TextEditingController(text: profileDetails.hipCircumference.toString())),
],
),
),
],
),
const 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)),
const SizedBox(height: 4),
CustomTextFormField(readOnly: true, controller: TextEditingController(text: profileDetails.bloodPressureUp.toString())),
],
),
),
const SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(s.lower, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
const SizedBox(height: 4),
CustomTextFormField(
readOnly: true,
controller: TextEditingController(text: profileDetails.bloodPressureDown.toStringAsFixed(0)),
),
],
),
),
],
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(s.has_hypo, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
const SizedBox(height: 4),
CustomTextFormField(readOnly: true, controller: TextEditingController(text: profileDetails.hasHypo ? 'да' : 'нет')),
],
),
),
const SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(s.has_hyper, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
const SizedBox(height: 4),
CustomTextFormField(readOnly: true, controller: TextEditingController(text: profileDetails.hasHyper ? 'да' : 'нет')),
],
),
),
],
),
const SizedBox(height: 16),
],
),
ExpandableBouble(
title: s.other_info,
children: [
Text(s.has_alergy, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
const SizedBox(height: 4),
CustomTextFormField(readOnly: true, controller: TextEditingController(text: profileDetails.aboutAlergy)),
const SizedBox(height: 16),
Text(s.takes_pills, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
const SizedBox(height: 4),
CustomTextFormField(readOnly: true, controller: TextEditingController(text: profileDetails.aboutTakingPils)),
const SizedBox(height: 16),
Text(s.sport_hobbies, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
const SizedBox(height: 4),
CustomTextFormField(readOnly: true, controller: TextEditingController(text: profileDetails.aboutSportHobbies)),
const SizedBox(height: 16),
Text(s.liked_groceries, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
const SizedBox(height: 4),
CustomTextFormField(readOnly: true, controller: TextEditingController(text: profileDetails.favoriteFoods)),
const SizedBox(height: 16),
Text(s.not_liked_groceries, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
const SizedBox(height: 4),
CustomTextFormField(readOnly: true, controller: TextEditingController(text: profileDetails.unfavoriteFoods)),
const SizedBox(height: 16),
Text(s.additional_information, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
const 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),
),
),
const SizedBox(height: 16),
],
),
],
),
),
),
);
} else if (state.error != null) {
return Scaffold(
appBar: AppBar(),
body: DataErrorWidget(
onReload: () async {
context.read<UserDetailsCubit>().getUserDetails(widget.slug);
},
),
);
}
return Scaffold(appBar: AppBar(), body: const Loader());
},
);
}
}