forked from eatvio/eatvio_app
Imporoved state control for Profile Screen
This commit is contained in:
@@ -1,98 +1,154 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-20x20@1x.png",
|
||||
"scale" : "1x"
|
||||
"scale" : "2x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-20x20@2x.png",
|
||||
"scale" : "2x"
|
||||
"scale" : "3x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-20x20@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-29x29@1x.png",
|
||||
"scale" : "1x"
|
||||
"idiom" : "iphone",
|
||||
"scale" : "1x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"size" : "58x58",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-29x29@2x.png",
|
||||
"scale" : "2x"
|
||||
"scale" : "2x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"size" : "87x87",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-29x29@3x.png",
|
||||
"scale" : "3x"
|
||||
"scale" : "3x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"filename" : "Icon-App-20x20@2x.png",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-40x40@1x.png",
|
||||
"scale" : "1x"
|
||||
"scale" : "2x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"size" : "80x80",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-40x40@2x.png",
|
||||
"scale" : "2x"
|
||||
"scale" : "3x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"size" : "120x120",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-40x40@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "",
|
||||
"scale" : "3x"
|
||||
"scale" : "2x",
|
||||
"size" : "60x60"
|
||||
},
|
||||
{
|
||||
"filename" : "",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "60x60"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"filename" : "Icon-App-76x76@1x.png",
|
||||
"scale" : "1x"
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "76x76"
|
||||
},
|
||||
{
|
||||
"size" : "152x152",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "76x76"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "83.5x83.5"
|
||||
},
|
||||
{
|
||||
"idiom" : "ios-marketing",
|
||||
"scale" : "1x",
|
||||
"size" : "1024x1024"
|
||||
},
|
||||
{
|
||||
"filename" : "Icon-App-20x20@1x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "1x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"filename" : "Icon-App-40x40@1x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "1x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"filename" : "Icon-App-29x29@2x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "58x58"
|
||||
},
|
||||
{
|
||||
"filename" : "Icon-App-40x40@2x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "80x80"
|
||||
},
|
||||
{
|
||||
"filename" : "Icon-App-29x29@3x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "87x87"
|
||||
},
|
||||
{
|
||||
"filename" : "Icon-App-40x40@3x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "120x120"
|
||||
},
|
||||
{
|
||||
"filename" : "Icon-App-76x76@2x.png",
|
||||
"scale" : "2x"
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "152x152"
|
||||
},
|
||||
{
|
||||
"size" : "167x167",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-83.5x83.5@2x.png",
|
||||
"scale" : "2x"
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "167x167"
|
||||
},
|
||||
{
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-1024x1024@1x.png",
|
||||
"scale" : "1x"
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "1024x1024"
|
||||
},
|
||||
{
|
||||
"filename" : "Icon-App-20x20@3x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "60x60",
|
||||
"unassigned" : true
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "ios_icon_set"
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,4 +171,4 @@ class AuthScreen extends StatelessWidget {
|
||||
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,31 +15,8 @@ class MyProfileBloc extends Bloc<MyProfileEvent, MyProfileState> {
|
||||
MyProfileBloc(MyProfileState initialState) : super(initialState) {
|
||||
on<MyProfileInitialEvent>(_onInitialize);
|
||||
}
|
||||
Stream<MyProfileState> mapEventToState(MyProfileEvent event) async* {
|
||||
if (event is LogoutEvent) {
|
||||
// Удаление токенов из баз данных Hive и Laravel Sanctum
|
||||
var box = await Hive.openBox('myBox');
|
||||
final token = box.get('token');
|
||||
box.delete('token');
|
||||
|
||||
final response = await http.post(
|
||||
Uri.parse(dotenv.env['SERVER_ROOT']! + '/profile/logout'),
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
},
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
// Токен Laravel Sanctum успешно удален из базы данных
|
||||
} else {
|
||||
// Обработка ошибки
|
||||
}
|
||||
|
||||
// Перенаправление пользователя на экран AuthScreen
|
||||
}
|
||||
}
|
||||
|
||||
_onInitialize(
|
||||
Future<void> _onInitialize(
|
||||
MyProfileInitialEvent event,
|
||||
Emitter<MyProfileState> emit,
|
||||
) async {
|
||||
@@ -52,17 +29,35 @@ class MyProfileBloc extends Bloc<MyProfileEvent, MyProfileState> {
|
||||
},
|
||||
);
|
||||
final data = jsonDecode(response.body);
|
||||
emit(state.copyWith(
|
||||
user: data['user'],
|
||||
userDetails: data['userDetails'],
|
||||
token: token,
|
||||
chartPoints: data['chartPoints'],
|
||||
plans: data['plans'],
|
||||
chestCircumferenceController: TextEditingController(),
|
||||
waistCircumferenceController: TextEditingController(),
|
||||
hipCircumferenceController: TextEditingController(),
|
||||
weightController: TextEditingController(),
|
||||
circumferences: data['circumferences'],
|
||||
));
|
||||
|
||||
if (state is MyProfileLoadedState) {
|
||||
// Если текущее состояние уже загружено, обновляем его
|
||||
emit((state as MyProfileLoadedState).copyWith(
|
||||
user: data['user'],
|
||||
userDetails: data['userDetails'],
|
||||
token: token,
|
||||
chartPoints: data['chartPoints'],
|
||||
plans: data['plans'],
|
||||
chestCircumferenceController: TextEditingController(),
|
||||
waistCircumferenceController: TextEditingController(),
|
||||
hipCircumferenceController: TextEditingController(),
|
||||
weightController: TextEditingController(),
|
||||
circumferences: data['circumferences'],
|
||||
));
|
||||
} else {
|
||||
// Если текущее состояние - начальное, создаем новое загруженное состояние
|
||||
emit(MyProfileLoadedState(
|
||||
user: data['user'],
|
||||
userDetails: data['userDetails'],
|
||||
token: token,
|
||||
chartPoints: data['chartPoints'],
|
||||
plans: data['plans'],
|
||||
chestCircumferenceController: TextEditingController(),
|
||||
waistCircumferenceController: TextEditingController(),
|
||||
hipCircumferenceController: TextEditingController(),
|
||||
weightController: TextEditingController(),
|
||||
circumferences: data['circumferences'],
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,21 @@
|
||||
// ignore_for_file: must_be_immutable
|
||||
|
||||
part of 'my_profile_bloc.dart';
|
||||
|
||||
/// Represents the state of MyProfile in the application.
|
||||
class MyProfileState extends Equatable {
|
||||
MyProfileState(
|
||||
const MyProfileState({this.myProfileModelObj});
|
||||
|
||||
final MyProfileModel? myProfileModelObj;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [myProfileModelObj];
|
||||
}
|
||||
|
||||
class MyProfileInitialState extends MyProfileState {
|
||||
MyProfileInitialState({required MyProfileModel myProfileModelObj}) : super(myProfileModelObj: myProfileModelObj);
|
||||
}
|
||||
/// Represents the state of MyProfile in the application.
|
||||
class MyProfileLoadedState extends MyProfileState {
|
||||
MyProfileLoadedState(
|
||||
{this.chestCircumferenceController,
|
||||
this.waistCircumferenceController,
|
||||
this.hipCircumferenceController,
|
||||
@@ -15,7 +26,7 @@ class MyProfileState extends Equatable {
|
||||
this.chartPoints,
|
||||
this.plans,
|
||||
this.token,
|
||||
this.circumferences});
|
||||
this.circumferences}) : super(myProfileModelObj: null);
|
||||
|
||||
MyProfileModel? myProfileModelObj;
|
||||
Map<String, dynamic>? user;
|
||||
@@ -42,7 +53,7 @@ class MyProfileState extends Equatable {
|
||||
hipCircumferenceController,
|
||||
token
|
||||
];
|
||||
MyProfileState copyWith({
|
||||
MyProfileLoadedState copyWith({
|
||||
MyProfileModel? myProfileModelObj,
|
||||
Map<String, dynamic>? user,
|
||||
Map<String, dynamic>? userDetails,
|
||||
@@ -55,7 +66,7 @@ class MyProfileState extends Equatable {
|
||||
TextEditingController? hipCircumferenceController,
|
||||
String? token,
|
||||
}) {
|
||||
return MyProfileState(
|
||||
return MyProfileLoadedState(
|
||||
myProfileModelObj: myProfileModelObj ?? this.myProfileModelObj,
|
||||
user: user ?? this.user,
|
||||
plans: plans ?? this.plans,
|
||||
@@ -73,3 +84,4 @@ class MyProfileState extends Equatable {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,11 +29,25 @@ class MyProfileScreen extends StatelessWidget {
|
||||
child: MyProfileScreen());
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
mediaQueryData = MediaQuery.of(context);
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<MyProfileBloc, MyProfileState>(
|
||||
builder: (context, state) {
|
||||
builder: (context, state) {
|
||||
if (state is MyProfileInitialState) {
|
||||
// Это начальное состояние, данные ещё не загружены.
|
||||
return CircularProgressIndicator();
|
||||
} else if (state is MyProfileLoadedState) {
|
||||
// Данные загружены, можно строить экран.
|
||||
return _buildMyProfileScreen(context, state);
|
||||
} else {
|
||||
// Другие состояния, если они есть.
|
||||
return Container(); // Пустой контейнер для необработанных состояний.
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildMyProfileScreen(BuildContext context, MyProfileLoadedState state) {
|
||||
mediaQueryData = MediaQuery.of(context);
|
||||
return SafeArea(
|
||||
child: Scaffold(
|
||||
appBar: _buildAppBar(
|
||||
@@ -133,15 +147,6 @@ class MyProfileScreen extends StatelessWidget {
|
||||
.toList()),
|
||||
_buildChartLegend()
|
||||
]));
|
||||
/*case 4:
|
||||
return NextStepButton(
|
||||
buttonStyle:
|
||||
CustomButtonStyles.outlinePrimaryTL15,
|
||||
text: "тест".toUpperCase(),
|
||||
margin: EdgeInsets.only(left: 10.h),
|
||||
onPressed: () {
|
||||
print(dotenv.env['STORAGE_URL']!);
|
||||
});*/
|
||||
default:
|
||||
return Text('text',
|
||||
style: TextStyle(fontSize: 16.0));
|
||||
@@ -160,7 +165,6 @@ class MyProfileScreen extends StatelessWidget {
|
||||
SizedBox(height: 5.v),
|
||||
])),
|
||||
bottomNavigationBar: _buildBottomBar(context)));
|
||||
});
|
||||
}
|
||||
|
||||
/// Section Widget
|
||||
@@ -752,7 +756,7 @@ class MyProfileScreen extends StatelessWidget {
|
||||
return bmiList;
|
||||
}
|
||||
|
||||
_editCircumference(BuildContext context, MyProfileState state) {
|
||||
_editCircumference(BuildContext context, MyProfileLoadedState state) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
@@ -857,7 +861,7 @@ class MyProfileScreen extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
_editWeight(BuildContext context, MyProfileState state) {
|
||||
_editWeight(BuildContext context, MyProfileLoadedState state) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
|
||||
@@ -19,12 +19,25 @@ class MySettingsScreen extends StatelessWidget {
|
||||
child: MySettingsScreen());
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
mediaQueryData = MediaQuery.of(context);
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<MyProfileBloc, MyProfileState>(
|
||||
builder: (context, state) {
|
||||
print(state.userDetails);
|
||||
builder: (context, state) {
|
||||
if (state is MyProfileInitialState) {
|
||||
// Это начальное состояние, данные ещё не загружены.
|
||||
return CircularProgressIndicator();
|
||||
} else if (state is MyProfileLoadedState) {
|
||||
// Данные загружены, можно строить экран.
|
||||
return _buildSetingsScreen(context, state);
|
||||
} else {
|
||||
// Другие состояния, если они есть.
|
||||
return Container(); // Пустой контейнер для необработанных состояний.
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSetingsScreen(BuildContext context, MyProfileLoadedState state) {
|
||||
mediaQueryData = MediaQuery.of(context);
|
||||
final List<String> userDetails = [
|
||||
state.userDetails!['first_name'],
|
||||
state.userDetails!['last_name'],
|
||||
@@ -54,7 +67,6 @@ class MySettingsScreen extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
bottomNavigationBar: _buildBottomBar(context)));
|
||||
});
|
||||
}
|
||||
|
||||
/// Section Widget
|
||||
|
||||
@@ -76,10 +76,10 @@ class AdditionalInformationScreen extends StatelessWidget {
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: json.encode(sheet),
|
||||
);
|
||||
var res = await jsonDecode(response.body);
|
||||
final box = await Hive.openBox('token');
|
||||
final token = json.decode(response.body)['token'];
|
||||
final token = res['token']['plainTextToken'];
|
||||
box.put('token', token);
|
||||
print('token: ${box.get('token')}');
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
AppRoutes.myProfile,
|
||||
|
||||
@@ -64,11 +64,11 @@ class _FavoriteFoodsScreenState extends State<FavoriteFoodsScreen> {
|
||||
overflow: TextOverflow.ellipsis,
|
||||
textAlign: TextAlign.center,
|
||||
style: theme.textTheme.headlineSmall)),
|
||||
SizedBox(height: 23.v),
|
||||
SizedBox(height: 13.v),
|
||||
_buildTextFormFieldFav(context),
|
||||
SizedBox(height: 22.v),
|
||||
SizedBox(height: 12.v),
|
||||
_buildTextFormFieldUnfav(context),
|
||||
SizedBox(height: 27.v),
|
||||
SizedBox(height: 17.v),
|
||||
BlocBuilder<FavoriteFoodsBloc, FavoriteFoodsState>(
|
||||
builder: (context, state) {
|
||||
return NextStepButton(
|
||||
|
||||
@@ -83,17 +83,6 @@ class LanguageSelectScreen extends StatelessWidget {
|
||||
});
|
||||
}),
|
||||
Spacer(flex: 63),
|
||||
NextStepButton(
|
||||
text: "тест профиля".toUpperCase(),
|
||||
margin: EdgeInsets.only(
|
||||
left: 16.h, right: 16.h, bottom: 50.v),
|
||||
buttonStyle: CustomButtonStyles.outlinePrimaryTL15,
|
||||
onPressed: () {
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
AppRoutes.myProfile,
|
||||
);
|
||||
}),
|
||||
])),
|
||||
bottomNavigationBar:
|
||||
BlocBuilder<LanguageSelectBloc, LanguageSelectState>(
|
||||
|
||||
Reference in New Issue
Block a user