forked from eatvio/eatvio_app
Merge pull request 'build 70' (#646) from main into test-flight
Reviewed-on: eatvio/eatvio_app#646
This commit is contained in:
@@ -3,7 +3,7 @@ name: Eatvio App Android Test
|
||||
on: [ pull_request ]
|
||||
|
||||
env:
|
||||
flutter_version: "3.32.8"
|
||||
flutter_version: "3.35.1"
|
||||
java_version: "21.x"
|
||||
flutter_channel: "stable"
|
||||
my_local_cache_dir: "/opt/hostedtoolcache/"
|
||||
@@ -144,7 +144,11 @@ jobs:
|
||||
run: flutter test
|
||||
|
||||
- name: Build apk
|
||||
run: flutter build apk --release --dart-define=HIDE_PLANS=false
|
||||
run: |
|
||||
BUILD_DATE=$(TZ=Europe/Moscow date +'%Y-%m-%d %H:%M:%S')
|
||||
flutter build apk --release \
|
||||
--dart-define=HIDE_PLANS=false \
|
||||
--dart-define=BUILD_DATE="$BUILD_DATE"
|
||||
|
||||
- name: Rename and move apk
|
||||
run: |
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -16,6 +16,4 @@
|
||||
*.mocks.dart
|
||||
android/build/
|
||||
ios/XCBuildData/
|
||||
.env
|
||||
env.example
|
||||
env/.env
|
||||
env/.env
|
||||
@@ -29,7 +29,7 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.eatvioapp.app"
|
||||
minSdk = 23
|
||||
minSdkVersion flutter.minSdkVersion
|
||||
targetSdk = flutter.targetSdkVersion
|
||||
versionCode = flutter.versionCode
|
||||
versionName = flutter.versionName
|
||||
|
||||
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-all.zip
|
||||
|
||||
@@ -18,11 +18,11 @@ pluginManagement {
|
||||
|
||||
plugins {
|
||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||
id "com.android.application" version "8.7.3" apply false
|
||||
id "com.android.application" version "8.12.0" apply false
|
||||
// START: FlutterFire Configuration
|
||||
id "com.google.gms.google-services" version "4.4.2" apply false
|
||||
id "com.google.gms.google-services" version "4.4.3" apply false
|
||||
// END: FlutterFire Configuration
|
||||
id "org.jetbrains.kotlin.android" version "2.1.0" apply false
|
||||
id "org.jetbrains.kotlin.android" version "2.2.10" apply false
|
||||
}
|
||||
|
||||
include ":app"
|
||||
|
||||
@@ -396,7 +396,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Distribution: ITVIO, OOO (VL68C36HYS)";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 68;
|
||||
CURRENT_PROJECT_VERSION = 69;
|
||||
DEVELOPMENT_TEAM = VL68C36HYS;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
@@ -546,7 +546,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Distribution: ITVIO, OOO (VL68C36HYS)";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 68;
|
||||
CURRENT_PROJECT_VERSION = 69;
|
||||
DEVELOPMENT_TEAM = VL68C36HYS;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
@@ -584,7 +584,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Distribution: ITVIO, OOO (VL68C36HYS)";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 68;
|
||||
CURRENT_PROJECT_VERSION = 69;
|
||||
DEVELOPMENT_TEAM = VL68C36HYS;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>68</string>
|
||||
<string>69</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
|
||||
@@ -46,13 +46,15 @@ platform :ios do
|
||||
|
||||
match(type: "appstore", readonly: true)
|
||||
increment_build_number(xcodeproj: "Runner.xcodeproj")
|
||||
|
||||
build_date = Time.now.getlocal("+03:00").strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
build_app(
|
||||
workspace: "Runner.xcworkspace",
|
||||
scheme: "Runner",
|
||||
export_method: "app-store",
|
||||
codesigning_identity: "Apple Distribution",
|
||||
xcargs: "--dart-define=HIDE_PLANS=true"
|
||||
xcargs: "--dart-define=HIDE_PLANS=true --dart-define=BUILD_DATE='#{build_date}'"
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:eatvio_app/core/env_config.dart';
|
||||
|
||||
String baseUrl = EnvConfig.baseUrl;
|
||||
bool hidePlans = const bool.fromEnvironment('HIDE_PLANS', defaultValue: false);
|
||||
const buildDate = String.fromEnvironment('BUILD_DATE', defaultValue: '');
|
||||
|
||||
const List<int> durationValues = [7, 14, 21];
|
||||
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
|
||||
abstract class CredentialsStorage {
|
||||
static Future<bool> haveCredentialsInStorage() async {
|
||||
try {
|
||||
if (await const FlutterSecureStorage().read(key: 'email') == null || await const FlutterSecureStorage().read(key: 'password') == null) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<Map<String, String>> getCredentialsFromStorage() async {
|
||||
return {
|
||||
'email': (await const FlutterSecureStorage().read(key: 'email'))!,
|
||||
'password': (await const FlutterSecureStorage().read(key: 'password'))!,
|
||||
};
|
||||
}
|
||||
|
||||
static Future<void> saveCredentials(String email, String password) async {
|
||||
await const FlutterSecureStorage().write(key: 'email', value: email);
|
||||
await const FlutterSecureStorage().write(key: 'password', value: password);
|
||||
}
|
||||
|
||||
static Future<void> removeCredentials() async {
|
||||
await const FlutterSecureStorage().delete(key: 'email');
|
||||
await const FlutterSecureStorage().delete(key: 'password');
|
||||
}
|
||||
}
|
||||
@@ -107,7 +107,6 @@ import 'package:eatvio_app/features/settings/presentation/bloc/settings_cubit/se
|
||||
import 'package:eatvio_app/features/settings/repositories/service_repository.dart';
|
||||
import 'package:eatvio_app/features/settings/services/settings_service.dart';
|
||||
import 'package:eatvio_app/features/user_details/presentation/cubit/user_details_cubit.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:eatvio_app/features/profile/presentation/bloc/plans_cubit/plans_cubit.dart' as profile_plans;
|
||||
|
||||
@@ -252,5 +251,4 @@ Future<void> init() async {
|
||||
],
|
||||
),
|
||||
);
|
||||
sl.registerLazySingleton(() async => const FlutterSecureStorage());
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
abstract class TokenStorage {
|
||||
static Future<bool> haveTokenInStorage() async {
|
||||
final sharedPreferences = await SharedPreferences.getInstance();
|
||||
try {
|
||||
if (await const FlutterSecureStorage().read(key: 'token') == null) {
|
||||
if (sharedPreferences.getString('token') == null) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
@@ -13,19 +14,27 @@ abstract class TokenStorage {
|
||||
}
|
||||
}
|
||||
|
||||
static Future<String?> getTokenFromStorage() async => await const FlutterSecureStorage().read(key: 'token');
|
||||
|
||||
static Future<void> saveTokenInStorage(String token) async {
|
||||
await const FlutterSecureStorage().write(key: 'token', value: token);
|
||||
static Future<String?> getTokenFromStorage() async {
|
||||
final sharedPreferences = await SharedPreferences.getInstance();
|
||||
return sharedPreferences.getString('token');
|
||||
}
|
||||
|
||||
static Future<void> removeTokenInStorage() async => (await const FlutterSecureStorage().delete(key: 'token'));
|
||||
static Future<void> saveTokenInStorage(String token) async {
|
||||
final sharedPreferences = await SharedPreferences.getInstance();
|
||||
await sharedPreferences.setString('token', token);
|
||||
}
|
||||
|
||||
static Future<void> removeTokenInStorage() async {
|
||||
final sharedPreferences = await SharedPreferences.getInstance();
|
||||
await sharedPreferences.remove('token');
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SocketIdStorage {
|
||||
static Future<bool> haveSocketIdInStorage() async {
|
||||
final sharedPreferences = await SharedPreferences.getInstance();
|
||||
try {
|
||||
if (await const FlutterSecureStorage().read(key: 'socketId') == null) {
|
||||
if (sharedPreferences.getString('socketId') == null) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
@@ -35,11 +44,18 @@ abstract class SocketIdStorage {
|
||||
}
|
||||
}
|
||||
|
||||
static Future<String?> getSocketIdFromStorage() async => await const FlutterSecureStorage().read(key: 'socketId');
|
||||
|
||||
static Future<void> saveSocketIdInStorage(String socketId) async {
|
||||
await const FlutterSecureStorage().write(key: 'socketId', value: socketId);
|
||||
static Future<String?> getSocketIdFromStorage() async {
|
||||
final sharedPreferences = await SharedPreferences.getInstance();
|
||||
return sharedPreferences.getString('socketId');
|
||||
}
|
||||
|
||||
static Future<void> removeSocketIdInStorage() async => (await const FlutterSecureStorage().delete(key: 'socketId'));
|
||||
static Future<void> saveSocketIdInStorage(String socketId) async {
|
||||
final sharedPreferences = await SharedPreferences.getInstance();
|
||||
await sharedPreferences.setString('socketId', socketId);
|
||||
}
|
||||
|
||||
static Future<void> removeSocketIdInStorage() async {
|
||||
final sharedPreferences = await SharedPreferences.getInstance();
|
||||
await sharedPreferences.remove('socketId');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,8 @@ import 'package:eatvio_app/core/data/selectionPopupModel/selection_popup_model.d
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CustomDropDown extends StatelessWidget {
|
||||
const CustomDropDown({super.key,
|
||||
const CustomDropDown({
|
||||
super.key,
|
||||
this.alignment,
|
||||
this.width,
|
||||
this.focusNode,
|
||||
@@ -48,12 +49,7 @@ class CustomDropDown extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return alignment != null
|
||||
? Align(
|
||||
alignment: alignment ?? Alignment.center,
|
||||
child: _buildDropDownWidget(context),
|
||||
)
|
||||
: _buildDropDownWidget(context);
|
||||
return alignment != null ? Align(alignment: alignment ?? Alignment.center, child: _buildDropDownWidget(context)) : _buildDropDownWidget(context);
|
||||
}
|
||||
|
||||
DropdownButtonFormField<SelectionPopupModel> _buildDropDownWidget(BuildContext context) {
|
||||
@@ -61,7 +57,7 @@ class CustomDropDown extends StatelessWidget {
|
||||
focusNode: focusNode ?? FocusNode(),
|
||||
icon: const Icon(Icons.keyboard_arrow_down_rounded),
|
||||
autofocus: autofocus!,
|
||||
value: value,
|
||||
initialValue: value,
|
||||
isDense: true,
|
||||
isExpanded: true,
|
||||
items: items?.map((SelectionPopupModel item) {
|
||||
@@ -69,12 +65,7 @@ class CustomDropDown extends StatelessWidget {
|
||||
value: item,
|
||||
child: Text(
|
||||
item.title,
|
||||
style: hintStyle ??
|
||||
const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Colors.black,
|
||||
),
|
||||
style: hintStyle ?? const TextStyle(fontSize: 16, fontWeight: FontWeight.w400, color: Colors.black),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
@@ -90,19 +81,9 @@ class CustomDropDown extends StatelessWidget {
|
||||
|
||||
InputDecoration _buildInputDecoration(BuildContext context) {
|
||||
return InputDecoration(
|
||||
labelStyle: const TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
labelStyle: const TextStyle(fontSize: 16, color: Colors.black, fontWeight: FontWeight.w400),
|
||||
hintText: hintText ?? "",
|
||||
hintStyle: hintStyle ??
|
||||
TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Colors.grey.shade400,
|
||||
height: 1,
|
||||
),
|
||||
hintStyle: hintStyle ?? TextStyle(fontSize: 16, fontWeight: FontWeight.w400, color: Colors.grey.shade400, height: 1),
|
||||
prefixIcon: prefix,
|
||||
prefixIconConstraints: prefixConstraints,
|
||||
suffixIcon: suffix,
|
||||
@@ -111,18 +92,9 @@ class CustomDropDown extends StatelessWidget {
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 16, horizontal: 12),
|
||||
fillColor: const Color(0xFFF6F6F6),
|
||||
filled: filled,
|
||||
border: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(20)),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
enabledBorder: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(20)),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
focusedBorder: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(20)),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
border: const OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(20)), borderSide: BorderSide.none),
|
||||
enabledBorder: const OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(20)), borderSide: BorderSide.none),
|
||||
focusedBorder: const OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(20)), borderSide: BorderSide.none),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
||||
class CustomDropDownButton<T> extends StatelessWidget {
|
||||
const CustomDropDownButton({
|
||||
super.key,
|
||||
required this.items,
|
||||
required this.onChanged,
|
||||
this.value,
|
||||
this.hint,
|
||||
this.hasError = false,
|
||||
});
|
||||
const CustomDropDownButton({super.key, required this.items, required this.onChanged, this.value, this.hint, this.hasError = false});
|
||||
final T? value;
|
||||
final List<DropdownMenuItem<T>> items;
|
||||
final void Function(T?)? onChanged;
|
||||
@@ -20,11 +13,7 @@ class CustomDropDownButton<T> extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return DropdownButtonFormField(
|
||||
hint: hint,
|
||||
icon: SvgPicture.asset(
|
||||
'assets/icons/arrow_down2.svg',
|
||||
width: 12,
|
||||
height: 8,
|
||||
),
|
||||
icon: SvgPicture.asset('assets/icons/arrow_down2.svg', width: 12, height: 8),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
dropdownColor: appTheme.lightGray0,
|
||||
decoration: InputDecoration(
|
||||
@@ -43,7 +32,7 @@ class CustomDropDownButton<T> extends StatelessWidget {
|
||||
fillColor: appTheme.lightGray0,
|
||||
filled: true,
|
||||
),
|
||||
value: value,
|
||||
initialValue: value,
|
||||
items: items,
|
||||
onChanged: onChanged,
|
||||
);
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'dart:io';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:eatvio_app/core/app_router.dart';
|
||||
import 'package:eatvio_app/core/const.dart';
|
||||
import 'package:eatvio_app/core/firebase_api.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/token_storage.dart';
|
||||
import 'package:eatvio_app/core/utils/toasts.dart';
|
||||
@@ -92,6 +93,7 @@ class _ScanQRCodeScreenState extends State<ScanQRCodeScreen> {
|
||||
await sl<ChatsCubit>().connectToWebSocket();
|
||||
await sl<NotificationsCubit>().getNotifications();
|
||||
await sl<NotificationsCubit>().connectToWebSocket();
|
||||
await sl<FirebaseApi>().registerPushToken();
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
|
||||
@@ -23,81 +23,105 @@ class _RegistrationAsScreenState extends State<RegistrationAsScreen> {
|
||||
children: [
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(
|
||||
'Регистрация в качестве',
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w700,
|
||||
height: 1.1,
|
||||
),
|
||||
),
|
||||
child: Text('Регистрация в качестве', style: TextStyle(fontSize: 24, fontWeight: FontWeight.w700, height: 1.1)),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
RadioListTile<RegistrationAsType>(
|
||||
value: RegistrationAsType.physical,
|
||||
groupValue: registrationAsType,
|
||||
title: const Text(
|
||||
'Физического лица',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
height: 1,
|
||||
Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Radio<RegistrationAsType>(
|
||||
value: RegistrationAsType.physical,
|
||||
// ignore: deprecated_member_use
|
||||
groupValue: registrationAsType,
|
||||
activeColor: appTheme.blueA400,
|
||||
// ignore: deprecated_member_use
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
registrationAsType = value!;
|
||||
});
|
||||
},
|
||||
),
|
||||
const Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||
child: Text('Физического лица', style: TextStyle(fontSize: 18, height: 1)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
activeColor: appTheme.blueA400,
|
||||
onChanged: (value) {},
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
),
|
||||
RadioListTile<RegistrationAsType>(
|
||||
value: RegistrationAsType.selfBusy,
|
||||
groupValue: registrationAsType,
|
||||
title: const Text(
|
||||
'Самозанятого',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
height: 1,
|
||||
Row(
|
||||
children: [
|
||||
Radio<RegistrationAsType>(
|
||||
value: RegistrationAsType.selfBusy,
|
||||
// ignore: deprecated_member_use
|
||||
groupValue: registrationAsType,
|
||||
activeColor: appTheme.blueA400,
|
||||
// ignore: deprecated_member_use
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
registrationAsType = value!;
|
||||
});
|
||||
},
|
||||
),
|
||||
const Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||
child: Text('Самозанятого', style: TextStyle(fontSize: 18, height: 1)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
onChanged: null,
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
),
|
||||
RadioListTile<RegistrationAsType>(
|
||||
value: RegistrationAsType.iP,
|
||||
groupValue: registrationAsType,
|
||||
title: const Text(
|
||||
'Индивидуального предпринимателя',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
height: 1,
|
||||
Row(
|
||||
children: [
|
||||
Radio<RegistrationAsType>(
|
||||
value: RegistrationAsType.iP,
|
||||
// ignore: deprecated_member_use
|
||||
groupValue: registrationAsType,
|
||||
activeColor: appTheme.blueA400,
|
||||
// ignore: deprecated_member_use
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
registrationAsType = value!;
|
||||
});
|
||||
},
|
||||
),
|
||||
const Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||
child: Text('Индивидуального предпринимателя', style: TextStyle(fontSize: 18, height: 1)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
onChanged: null,
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
),
|
||||
RadioListTile<RegistrationAsType>(
|
||||
value: RegistrationAsType.ooo,
|
||||
groupValue: registrationAsType,
|
||||
title: const Text(
|
||||
'Общества с ограниченной ответственностью',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
height: 1,
|
||||
Row(
|
||||
children: [
|
||||
Radio<RegistrationAsType>(
|
||||
value: RegistrationAsType.ooo,
|
||||
// ignore: deprecated_member_use
|
||||
groupValue: registrationAsType,
|
||||
activeColor: appTheme.blueA400,
|
||||
// ignore: deprecated_member_use
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
registrationAsType = value!;
|
||||
});
|
||||
},
|
||||
),
|
||||
const Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||
child: Text('Общества с ограниченной ответственностью', style: TextStyle(fontSize: 18, height: 1)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
onChanged: null,
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 16,
|
||||
),
|
||||
child: _divider(context),
|
||||
],
|
||||
),
|
||||
Padding(padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), child: _divider(context)),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(
|
||||
'* На данный момент регистрация доступна только в качестве физического лица. Остальные варианты скоро появятся',
|
||||
),
|
||||
child: Text('* На данный момент регистрация доступна только в качестве физического лица. Остальные варианты скоро появятся'),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -108,10 +132,7 @@ class _RegistrationAsScreenState extends State<RegistrationAsScreen> {
|
||||
return Container(
|
||||
height: 0.4,
|
||||
width: MediaQuery.of(context).size.width - 32,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black26,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
decoration: BoxDecoration(color: Colors.black26, borderRadius: BorderRadius.circular(16)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +156,13 @@ class _AppInfoState extends State<AppInfo> {
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsGeometry.only(left: 16),
|
||||
child: Text('Версия приложения: $version ($buildNumber)', style: TextStyles.textXSSemibold.copyWith(color: appTheme.gray)),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Версия приложения: $version ($buildNumber)', style: TextStyles.textXSSemibold.copyWith(color: appTheme.gray)),
|
||||
if (buildDate != '') Text('Дата сборки: $buildDate', style: TextStyles.textXSSemibold.copyWith(color: appTheme.gray)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -66,12 +66,6 @@ class NotificationsCubit extends Cubit<NotificationsState> {
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.chosenPlanFinishedToClient => ChosenPlanFinishedToClientNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.planSubscriptionCanceledToCustomer => PlanSubscriptionCanceledToAuthorNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
@@ -96,12 +90,6 @@ class NotificationsCubit extends Cubit<NotificationsState> {
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.chosenPlanFinishedToConsultant => ChosenPlanFinishedToConsultantNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.chosenPlanLastDayFinishedForUser => ChosenPlanLastDayFinishedForUser.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
@@ -123,6 +111,156 @@ class NotificationsCubit extends Cubit<NotificationsState> {
|
||||
NotificationType.goalAchieved => GoalAchievedNotification.fromJson(notificationJson, type, isRead: isRead, createdAt: createdAt),
|
||||
NotificationType.workoutReminder => WorkoutReminderNotification.fromJson(notificationJson, type, isRead: isRead, createdAt: createdAt),
|
||||
NotificationType.mealReminder => MealReminderNotification.fromJson(notificationJson, type, isRead: isRead, createdAt: createdAt),
|
||||
// New notification types
|
||||
NotificationType.dietCancelled => DietCancelledNotification.fromJson(notificationJson, type, isRead: isRead, createdAt: createdAt),
|
||||
NotificationType.dietStarted => DietStartedNotification.fromJson(notificationJson, type, isRead: isRead, createdAt: createdAt),
|
||||
NotificationType.dietExpired => DietExpiredNotification.fromJson(notificationJson, type, isRead: isRead, createdAt: createdAt),
|
||||
NotificationType.dietWillStartedIn => DietWillStartedInNotification.fromJson(notificationJson, type, isRead: isRead, createdAt: createdAt),
|
||||
NotificationType.dietCanNotBeStarted => DietCanNotBeStartedNotification.fromJson(notificationJson, type, isRead: isRead, createdAt: createdAt),
|
||||
NotificationType.personalDietCreationNeeded => PersonalDietCreationNeededNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.chosenPlanClientLastDayFinished => ChosenPlanClientLastDayFinishedNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.chosenPlanClientLastDayStarted => ChosenPlanClientLastDayStartedNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.stayOnTrackToAuthor => StayOnTrackToAuthorNotification.fromJson(notificationJson, type, isRead: isRead, createdAt: createdAt),
|
||||
NotificationType.chosenPlanStartedToClient => ChosenPlanStartedToClientNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.clientStartPlanSubscriptionToSubscriber => ClientStartPlanSubscriptionToSubscriberNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.consultantConfirmPlanSubscriptionToSubscriber => ConsultantConfirmPlanSubscriptionToSubscriberNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.clientPaidPlanSubscriptionToAuthor => ClientPaidPlanSubscriptionToAuthorNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.chosenPlanTomorrowReminderToClient => ChosenPlanTomorrowReminderToClientNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.chosenPlanTomorrowReminderToConsultant => ChosenPlanTomorrowReminderToConsultantNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.chosenPlanStartedToConsultant => ChosenPlanStartedToConsultantNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.consultantLeftDiaryComment => ConsultantLeftDiaryCommentNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.chosenPlanFinishedToClient => ChosenPlanFinishedToClientNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.consultantConfirmPlanSubscriptionToAuthor => ConsultantConfirmPlanSubscriptionToAuthorNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.clientPaidPlanSubscriptionToSubscriber => ClientPaidPlanSubscriptionToSubscriberNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.clientStartPlanSubscriptionToAuthor => ClientStartPlanSubscriptionToAuthorNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.clientCancelPlanSubscriptionToAuthor => ClientCancelPlanSubscriptionToAuthorNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.clientCancelPlanSubscriptionToSubscriber => ClientCancelPlanSubscriptionToSubscriberNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.userDailyReportCompleted => UserDailyReportCompletedNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.chosenPlanFinishedToConsultant => ChosenPlanFinishedToConsultantNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.stayOnTrackToCustomer => StayOnTrackToCustomerNotification.fromJson(notificationJson, type, isRead: isRead, createdAt: createdAt),
|
||||
NotificationType.phoneChanged => PhoneChangedNotification.fromJson(notificationJson, type, isRead: isRead, createdAt: createdAt),
|
||||
NotificationType.subscription => SubscriptionNotification.fromJson(notificationJson, type, isRead: isRead, createdAt: createdAt),
|
||||
NotificationType.badgeAwarded => BadgeAwardedNotification.fromJson(notificationJson, type, isRead: isRead, createdAt: createdAt),
|
||||
NotificationType.badgeRevoked => BadgeRevokedNotification.fromJson(notificationJson, type, isRead: isRead, createdAt: createdAt),
|
||||
NotificationType.consultantRequestStarted => ConsultantRequestStartedNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.clientCloseComplaintSuccess => ClientCloseComplaintSuccessNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.clientRefundSuccess => ClientRefundSuccessNotification.fromJson(notificationJson, type, isRead: isRead, createdAt: createdAt),
|
||||
NotificationType.consultantRefundSuccess => ConsultantRefundSuccessNotification.fromJson(notificationJson, type, isRead: isRead, createdAt: createdAt),
|
||||
NotificationType.clientRejectSuccess => ClientRejectSuccessNotification.fromJson(notificationJson, type, isRead: isRead, createdAt: createdAt),
|
||||
NotificationType.consultantRejectSuccess => ConsultantRejectSuccessNotification.fromJson(notificationJson, type, isRead: isRead, createdAt: createdAt),
|
||||
NotificationType.scoreSubstracted => ScoreSubstractedNotification.fromJson(notificationJson, type, isRead: isRead, createdAt: createdAt),
|
||||
NotificationType.productStatusUpdatedForAuthor => ProductStatusUpdatedForAuthorNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.diaryReminderForUsers => DiaryReminderForUsersNotification.fromJson(notificationJson, type, isRead: isRead, createdAt: createdAt),
|
||||
NotificationType.unknown => UnknownNotification(type: type),
|
||||
};
|
||||
} catch (e) {
|
||||
@@ -132,8 +270,36 @@ class NotificationsCubit extends Cubit<NotificationsState> {
|
||||
|
||||
void _handleNotification(String notificationData) {
|
||||
final json = jsonDecode(notificationData) as Map<String, dynamic>;
|
||||
final stringifiedType = json['notification_class_name'];
|
||||
final type = NotificationType.getTypeFromString(stringifiedType);
|
||||
|
||||
// Улучшенная логика определения типа уведомления
|
||||
String? stringifiedType;
|
||||
|
||||
// Сначала проверяем поле 'type' в корне JSON
|
||||
if (json.containsKey('type') && json['type'] != null) {
|
||||
stringifiedType = json['type'].toString();
|
||||
log('Found type in root: $stringifiedType');
|
||||
}
|
||||
// Затем проверяем поле 'notification_class_name' в корне JSON
|
||||
else if (json.containsKey('notification_class_name') && json['notification_class_name'] != null) {
|
||||
stringifiedType = json['notification_class_name'].toString();
|
||||
log('Found notification_class_name in root: $stringifiedType');
|
||||
}
|
||||
// Если есть поле 'data', проверяем внутри него
|
||||
else if (json.containsKey('data') && json['data'] is Map<String, dynamic>) {
|
||||
final data = json['data'] as Map<String, dynamic>;
|
||||
if (data.containsKey('type') && data['type'] != null) {
|
||||
stringifiedType = data['type'].toString();
|
||||
log('Found type in data: $stringifiedType');
|
||||
} else if (data.containsKey('notification_class_name') && data['notification_class_name'] != null) {
|
||||
stringifiedType = data['notification_class_name'].toString();
|
||||
log('Found notification_class_name in data: $stringifiedType');
|
||||
}
|
||||
}
|
||||
|
||||
// Если тип не найден, используем unknown
|
||||
final type = stringifiedType != null ? NotificationType.getTypeFromString(stringifiedType) : NotificationType.unknown;
|
||||
log('Final type: $type, stringifiedType: $stringifiedType');
|
||||
|
||||
final notification = _parseNotification(json, type);
|
||||
_notifications.insert(0, notification);
|
||||
|
||||
|
||||
@@ -57,6 +57,62 @@ class NotificationWidget extends StatelessWidget {
|
||||
GoalAchievedNotification() => _GoalAchievedWidget(notification: notification as GoalAchievedNotification),
|
||||
WorkoutReminderNotification() => _WorkoutReminderWidget(notification: notification as WorkoutReminderNotification),
|
||||
MealReminderNotification() => _MealReminderWidget(notification: notification as MealReminderNotification),
|
||||
// New notification types
|
||||
DietCancelledNotification() => _DietCancelledWidget(notification: notification as DietCancelledNotification),
|
||||
DietStartedNotification() => _DietStartedWidget(notification: notification as DietStartedNotification),
|
||||
DietExpiredNotification() => _DietExpiredWidget(notification: notification as DietExpiredNotification),
|
||||
DietWillStartedInNotification() => _DietWillStartedInWidget(notification: notification as DietWillStartedInNotification),
|
||||
DietCanNotBeStartedNotification() => _DietCanNotBeStartedWidget(notification: notification as DietCanNotBeStartedNotification),
|
||||
PersonalDietCreationNeededNotification() => _PersonalDietCreationNeededWidget(notification: notification as PersonalDietCreationNeededNotification),
|
||||
ChosenPlanClientLastDayFinishedNotification() => _ChosenPlanClientLastDayFinishedWidget(
|
||||
notification: notification as ChosenPlanClientLastDayFinishedNotification,
|
||||
),
|
||||
ChosenPlanClientLastDayStartedNotification() => _ChosenPlanClientLastDayStartedWidget(
|
||||
notification: notification as ChosenPlanClientLastDayStartedNotification,
|
||||
),
|
||||
StayOnTrackToAuthorNotification() => _StayOnTrackToAuthorWidget(notification: notification as StayOnTrackToAuthorNotification),
|
||||
ClientStartPlanSubscriptionToSubscriberNotification() => _ClientStartPlanSubscriptionToSubscriberWidget(
|
||||
notification: notification as ClientStartPlanSubscriptionToSubscriberNotification,
|
||||
),
|
||||
ConsultantConfirmPlanSubscriptionToSubscriberNotification() => _ConsultantConfirmPlanSubscriptionToSubscriberWidget(
|
||||
notification: notification as ConsultantConfirmPlanSubscriptionToSubscriberNotification,
|
||||
),
|
||||
ClientPaidPlanSubscriptionToAuthorNotification() => _ClientPaidPlanSubscriptionToAuthorWidget(
|
||||
notification: notification as ClientPaidPlanSubscriptionToAuthorNotification,
|
||||
),
|
||||
ConsultantLeftDiaryCommentNotification() => _ConsultantLeftDiaryCommentWidget(notification: notification as ConsultantLeftDiaryCommentNotification),
|
||||
ConsultantConfirmPlanSubscriptionToAuthorNotification() => _ConsultantConfirmPlanSubscriptionToAuthorWidget(
|
||||
notification: notification as ConsultantConfirmPlanSubscriptionToAuthorNotification,
|
||||
),
|
||||
ClientPaidPlanSubscriptionToSubscriberNotification() => _ClientPaidPlanSubscriptionToSubscriberWidget(
|
||||
notification: notification as ClientPaidPlanSubscriptionToSubscriberNotification,
|
||||
),
|
||||
ClientStartPlanSubscriptionToAuthorNotification() => _ClientStartPlanSubscriptionToAuthorWidget(
|
||||
notification: notification as ClientStartPlanSubscriptionToAuthorNotification,
|
||||
),
|
||||
ClientCancelPlanSubscriptionToAuthorNotification() => _ClientCancelPlanSubscriptionToAuthorWidget(
|
||||
notification: notification as ClientCancelPlanSubscriptionToAuthorNotification,
|
||||
),
|
||||
ClientCancelPlanSubscriptionToSubscriberNotification() => _ClientCancelPlanSubscriptionToSubscriberWidget(
|
||||
notification: notification as ClientCancelPlanSubscriptionToSubscriberNotification,
|
||||
),
|
||||
UserDailyReportCompletedNotification() => _UserDailyReportCompletedWidget(notification: notification as UserDailyReportCompletedNotification),
|
||||
StayOnTrackToCustomerNotification() => _StayOnTrackToCustomerWidget(notification: notification as StayOnTrackToCustomerNotification),
|
||||
PhoneChangedNotification() => _PhoneChangedWidget(notification: notification as PhoneChangedNotification),
|
||||
SubscriptionNotification() => _SubscriptionWidget(notification: notification as SubscriptionNotification),
|
||||
BadgeAwardedNotification() => _BadgeAwardedWidget(notification: notification as BadgeAwardedNotification),
|
||||
BadgeRevokedNotification() => _BadgeRevokedWidget(notification: notification as BadgeRevokedNotification),
|
||||
ConsultantRequestStartedNotification() => _ConsultantRequestStartedWidget(notification: notification as ConsultantRequestStartedNotification),
|
||||
ClientCloseComplaintSuccessNotification() => _ClientCloseComplaintSuccessWidget(notification: notification as ClientCloseComplaintSuccessNotification),
|
||||
ClientRefundSuccessNotification() => _ClientRefundSuccessWidget(notification: notification as ClientRefundSuccessNotification),
|
||||
ConsultantRefundSuccessNotification() => _ConsultantRefundSuccessWidget(notification: notification as ConsultantRefundSuccessNotification),
|
||||
ClientRejectSuccessNotification() => _ClientRejectSuccessWidget(notification: notification as ClientRejectSuccessNotification),
|
||||
ConsultantRejectSuccessNotification() => _ConsultantRejectSuccessWidget(notification: notification as ConsultantRejectSuccessNotification),
|
||||
ScoreSubstractedNotification() => _ScoreSubstractedWidget(notification: notification as ScoreSubstractedNotification),
|
||||
ProductStatusUpdatedForAuthorNotification() => _ProductStatusUpdatedForAuthorWidget(
|
||||
notification: notification as ProductStatusUpdatedForAuthorNotification,
|
||||
),
|
||||
DiaryReminderForUsersNotification() => _DiaryReminderForUsersWidget(notification: notification as DiaryReminderForUsersNotification),
|
||||
UnknownNotification() => _UnknownNotificationWidget(notification: notification as UnknownNotification),
|
||||
};
|
||||
}
|
||||
@@ -571,3 +627,429 @@ class _MealReminderWidget extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// New notification widget classes
|
||||
class _DietCancelledWidget extends StatelessWidget {
|
||||
const _DietCancelledWidget({required this.notification});
|
||||
final DietCancelledNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Диета "${notification.dietName}" отменена',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _DietStartedWidget extends StatelessWidget {
|
||||
const _DietStartedWidget({required this.notification});
|
||||
final DietStartedNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Диета "${notification.dietName}" началась',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _DietExpiredWidget extends StatelessWidget {
|
||||
const _DietExpiredWidget({required this.notification});
|
||||
final DietExpiredNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Диета "${notification.dietName}" истекла',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _DietWillStartedInWidget extends StatelessWidget {
|
||||
const _DietWillStartedInWidget({required this.notification});
|
||||
final DietWillStartedInNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Диета "${notification.dietName}" начнется ${notification.startDate}',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _DietCanNotBeStartedWidget extends StatelessWidget {
|
||||
const _DietCanNotBeStartedWidget({required this.notification});
|
||||
final DietCanNotBeStartedNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Диета "${notification.dietName}" не может быть начата: ${notification.reason}',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _PersonalDietCreationNeededWidget extends StatelessWidget {
|
||||
const _PersonalDietCreationNeededWidget({required this.notification});
|
||||
final PersonalDietCreationNeededNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Требуется создание персональной диеты для клиента ${notification.clientName} по плану "${notification.planName}"',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ChosenPlanClientLastDayFinishedWidget extends StatelessWidget {
|
||||
const _ChosenPlanClientLastDayFinishedWidget({required this.notification});
|
||||
final ChosenPlanClientLastDayFinishedNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Последний день плана "${notification.planName}" завершен',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ChosenPlanClientLastDayStartedWidget extends StatelessWidget {
|
||||
const _ChosenPlanClientLastDayStartedWidget({required this.notification});
|
||||
final ChosenPlanClientLastDayStartedNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Последний день плана "${notification.planName}" начался',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _StayOnTrackToAuthorWidget extends StatelessWidget {
|
||||
const _StayOnTrackToAuthorWidget({required this.notification});
|
||||
final StayOnTrackToAuthorNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Клиент ${notification.clientName} остается на плане "${notification.planName}"',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ClientStartPlanSubscriptionToSubscriberWidget extends StatelessWidget {
|
||||
const _ClientStartPlanSubscriptionToSubscriberWidget({required this.notification});
|
||||
final ClientStartPlanSubscriptionToSubscriberNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Подписка на план "${notification.planName}" началась',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ConsultantConfirmPlanSubscriptionToSubscriberWidget extends StatelessWidget {
|
||||
const _ConsultantConfirmPlanSubscriptionToSubscriberWidget({required this.notification});
|
||||
final ConsultantConfirmPlanSubscriptionToSubscriberNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Консультант ${notification.consultantName} подтвердил подписку на план "${notification.planName}"',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ClientPaidPlanSubscriptionToAuthorWidget extends StatelessWidget {
|
||||
const _ClientPaidPlanSubscriptionToAuthorWidget({required this.notification});
|
||||
final ClientPaidPlanSubscriptionToAuthorNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Клиент ${notification.clientName} оплатил подписку на план "${notification.planName}" на сумму ${notification.amount}',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ConsultantLeftDiaryCommentWidget extends StatelessWidget {
|
||||
const _ConsultantLeftDiaryCommentWidget({required this.notification});
|
||||
final ConsultantLeftDiaryCommentNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Консультант ${notification.consultantName} оставил комментарий к дневнику по плану "${notification.planName}"',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ConsultantConfirmPlanSubscriptionToAuthorWidget extends StatelessWidget {
|
||||
const _ConsultantConfirmPlanSubscriptionToAuthorWidget({required this.notification});
|
||||
final ConsultantConfirmPlanSubscriptionToAuthorNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Консультант ${notification.consultantName} подтвердил подписку на план "${notification.planName}"',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ClientPaidPlanSubscriptionToSubscriberWidget extends StatelessWidget {
|
||||
const _ClientPaidPlanSubscriptionToSubscriberWidget({required this.notification});
|
||||
final ClientPaidPlanSubscriptionToSubscriberNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Оплачена подписка на план "${notification.planName}" на сумму ${notification.amount}',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ClientStartPlanSubscriptionToAuthorWidget extends StatelessWidget {
|
||||
const _ClientStartPlanSubscriptionToAuthorWidget({required this.notification});
|
||||
final ClientStartPlanSubscriptionToAuthorNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Клиент ${notification.clientName} начал подписку на план "${notification.planName}"',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ClientCancelPlanSubscriptionToAuthorWidget extends StatelessWidget {
|
||||
const _ClientCancelPlanSubscriptionToAuthorWidget({required this.notification});
|
||||
final ClientCancelPlanSubscriptionToAuthorNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Клиент ${notification.clientName} отменил подписку на план "${notification.planName}"',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ClientCancelPlanSubscriptionToSubscriberWidget extends StatelessWidget {
|
||||
const _ClientCancelPlanSubscriptionToSubscriberWidget({required this.notification});
|
||||
final ClientCancelPlanSubscriptionToSubscriberNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Подписка на план "${notification.planName}" отменена',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _UserDailyReportCompletedWidget extends StatelessWidget {
|
||||
const _UserDailyReportCompletedWidget({required this.notification});
|
||||
final UserDailyReportCompletedNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Клиент ${notification.clientName} завершил ежедневный отчет по плану "${notification.planName}"',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _StayOnTrackToCustomerWidget extends StatelessWidget {
|
||||
const _StayOnTrackToCustomerWidget({required this.notification});
|
||||
final StayOnTrackToCustomerNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Консультант ${notification.consultantName} остается на плане "${notification.planName}"',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _PhoneChangedWidget extends StatelessWidget {
|
||||
const _PhoneChangedWidget({required this.notification});
|
||||
final PhoneChangedNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Номер телефона изменен с ${notification.oldPhone} на ${notification.newPhone}',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SubscriptionWidget extends StatelessWidget {
|
||||
const _SubscriptionWidget({required this.notification});
|
||||
final SubscriptionNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Подписка ${notification.subscriptionType} на план "${notification.planName}"',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _BadgeAwardedWidget extends StatelessWidget {
|
||||
const _BadgeAwardedWidget({required this.notification});
|
||||
final BadgeAwardedNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Получен значок "${notification.badgeName}": ${notification.badgeDescription}',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _BadgeRevokedWidget extends StatelessWidget {
|
||||
const _BadgeRevokedWidget({required this.notification});
|
||||
final BadgeRevokedNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Отозван значок "${notification.badgeName}": ${notification.reason}',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ConsultantRequestStartedWidget extends StatelessWidget {
|
||||
const _ConsultantRequestStartedWidget({required this.notification});
|
||||
final ConsultantRequestStartedNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Запрос к консультанту ${notification.consultantName} начат',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ClientCloseComplaintSuccessWidget extends StatelessWidget {
|
||||
const _ClientCloseComplaintSuccessWidget({required this.notification});
|
||||
final ClientCloseComplaintSuccessNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Жалоба на ${notification.complaintType} "${notification.entityName}" успешно закрыта',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ClientRefundSuccessWidget extends StatelessWidget {
|
||||
const _ClientRefundSuccessWidget({required this.notification});
|
||||
final ClientRefundSuccessNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Возврат средств по плану "${notification.planName}" на сумму ${notification.amount}: ${notification.reason}',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ConsultantRefundSuccessWidget extends StatelessWidget {
|
||||
const _ConsultantRefundSuccessWidget({required this.notification});
|
||||
final ConsultantRefundSuccessNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Возврат средств клиенту ${notification.clientName} по плану "${notification.planName}" на сумму ${notification.amount}',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ClientRejectSuccessWidget extends StatelessWidget {
|
||||
const _ClientRejectSuccessWidget({required this.notification});
|
||||
final ClientRejectSuccessNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Отклонение по плану "${notification.planName}": ${notification.reason}',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ConsultantRejectSuccessWidget extends StatelessWidget {
|
||||
const _ConsultantRejectSuccessWidget({required this.notification});
|
||||
final ConsultantRejectSuccessNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Отклонение клиентом ${notification.clientName} по плану "${notification.planName}": ${notification.reason}',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ScoreSubstractedWidget extends StatelessWidget {
|
||||
const _ScoreSubstractedWidget({required this.notification});
|
||||
final ScoreSubstractedNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Вычтено ${notification.scoreValue} баллов за ${notification.scorableName}',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ProductStatusUpdatedForAuthorWidget extends StatelessWidget {
|
||||
const _ProductStatusUpdatedForAuthorWidget({required this.notification});
|
||||
final ProductStatusUpdatedForAuthorNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Статус продукта "${notification.productName}" изменен с ${notification.oldStatus} на ${notification.newStatus}',
|
||||
createdAt: notification.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _DiaryReminderForUsersWidget extends StatelessWidget {
|
||||
const _DiaryReminderForUsersWidget({required this.notification});
|
||||
final DiaryReminderForUsersNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _BaseNotificationWidget(isRead: notification.isRead, notificationsText: 'Напоминание о заполнении дневника', createdAt: notification.createdAt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,10 +13,30 @@ class NotificationsService {
|
||||
|
||||
final notifications = data.map((notificationJson) {
|
||||
try {
|
||||
final stringifiedType = notificationJson['data']['notification_class_name'];
|
||||
// Улучшенная логика определения типа уведомления
|
||||
String? stringifiedType;
|
||||
|
||||
// Сначала проверяем поле 'type' в корне JSON
|
||||
if (notificationJson.containsKey('type') && notificationJson['type'] != null) {
|
||||
stringifiedType = notificationJson['type'].toString();
|
||||
}
|
||||
// Затем проверяем поле 'notification_class_name' в корне JSON
|
||||
else if (notificationJson.containsKey('notification_class_name') && notificationJson['notification_class_name'] != null) {
|
||||
stringifiedType = notificationJson['notification_class_name'].toString();
|
||||
}
|
||||
// Если есть поле 'data', проверяем внутри него
|
||||
else if (notificationJson.containsKey('data') && notificationJson['data'] is Map<String, dynamic>) {
|
||||
final data = notificationJson['data'] as Map<String, dynamic>;
|
||||
if (data.containsKey('type') && data['type'] != null) {
|
||||
stringifiedType = data['type'].toString();
|
||||
} else if (data.containsKey('notification_class_name') && data['notification_class_name'] != null) {
|
||||
stringifiedType = data['notification_class_name'].toString();
|
||||
}
|
||||
}
|
||||
|
||||
final readDate = notificationJson['read_at'];
|
||||
final createdAt = notificationJson['created_at'];
|
||||
final type = NotificationType.getTypeFromString(stringifiedType);
|
||||
final type = stringifiedType != null ? NotificationType.getTypeFromString(stringifiedType) : NotificationType.unknown;
|
||||
|
||||
return switch (type) {
|
||||
NotificationType.planSubscriptionStartedToAuthor => PlanSubscriptionStartedToAuthorNotification.fromJson(
|
||||
@@ -174,6 +194,219 @@ class NotificationsService {
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
// New notification types
|
||||
NotificationType.dietCancelled => DietCancelledNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.dietStarted => DietStartedNotification.fromJson(notificationJson['data'], type, isRead: readDate != null, createdAt: createdAt),
|
||||
NotificationType.dietExpired => DietExpiredNotification.fromJson(notificationJson['data'], type, isRead: readDate != null, createdAt: createdAt),
|
||||
NotificationType.dietWillStartedIn => DietWillStartedInNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.dietCanNotBeStarted => DietCanNotBeStartedNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.personalDietCreationNeeded => PersonalDietCreationNeededNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.chosenPlanClientLastDayFinished => ChosenPlanClientLastDayFinishedNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.chosenPlanClientLastDayStarted => ChosenPlanClientLastDayStartedNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.stayOnTrackToAuthor => StayOnTrackToAuthorNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.chosenPlanStartedToClient => ChosenPlanStartedToClientNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.clientStartPlanSubscriptionToSubscriber => ClientStartPlanSubscriptionToSubscriberNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.consultantConfirmPlanSubscriptionToSubscriber => ConsultantConfirmPlanSubscriptionToSubscriberNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.clientPaidPlanSubscriptionToAuthor => ClientPaidPlanSubscriptionToAuthorNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.chosenPlanTomorrowReminderToClient => ChosenPlanTomorrowReminderToClientNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.chosenPlanTomorrowReminderToConsultant => ChosenPlanTomorrowReminderToConsultantNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.chosenPlanStartedToConsultant => ChosenPlanStartedToConsultantNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.consultantLeftDiaryComment => ConsultantLeftDiaryCommentNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.consultantConfirmPlanSubscriptionToAuthor => ConsultantConfirmPlanSubscriptionToAuthorNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.clientPaidPlanSubscriptionToSubscriber => ClientPaidPlanSubscriptionToSubscriberNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.clientStartPlanSubscriptionToAuthor => ClientStartPlanSubscriptionToAuthorNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.clientCancelPlanSubscriptionToAuthor => ClientCancelPlanSubscriptionToAuthorNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.clientCancelPlanSubscriptionToSubscriber => ClientCancelPlanSubscriptionToSubscriberNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.userDailyReportCompleted => UserDailyReportCompletedNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.stayOnTrackToCustomer => StayOnTrackToCustomerNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.phoneChanged => PhoneChangedNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.subscription => SubscriptionNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.badgeAwarded => BadgeAwardedNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.badgeRevoked => BadgeRevokedNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.consultantRequestStarted => ConsultantRequestStartedNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.clientCloseComplaintSuccess => ClientCloseComplaintSuccessNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.clientRefundSuccess => ClientRefundSuccessNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.consultantRefundSuccess => ConsultantRefundSuccessNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.clientRejectSuccess => ClientRejectSuccessNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.consultantRejectSuccess => ConsultantRejectSuccessNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.scoreSubstracted => ScoreSubstractedNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.productStatusUpdatedForAuthor => ProductStatusUpdatedForAuthorNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.diaryReminderForUsers => DiaryReminderForUsersNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.unknown => UnknownNotification(type: type, createdAt: parseDate(createdAt)),
|
||||
};
|
||||
} catch (e) {
|
||||
|
||||
@@ -12,9 +12,7 @@ import 'package:eatvio_app/features/profile/services/profile_service.dart';
|
||||
class ProfileRepository {
|
||||
final ProfileService profileService;
|
||||
|
||||
ProfileRepository({
|
||||
required this.profileService,
|
||||
});
|
||||
ProfileRepository({required this.profileService});
|
||||
|
||||
Future<ProfileModel> getProfileBySlug(String slug) async {
|
||||
try {
|
||||
@@ -48,11 +46,7 @@ class ProfileRepository {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> addCircumference({
|
||||
required int chestCircumference,
|
||||
required int waistCircumference,
|
||||
required int hipCircumference,
|
||||
}) async {
|
||||
Future<void> addCircumference({required int chestCircumference, required int waistCircumference, required int hipCircumference}) async {
|
||||
try {
|
||||
return (await profileService.addCircumference(
|
||||
chestCircumference: chestCircumference,
|
||||
@@ -64,9 +58,7 @@ class ProfileRepository {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> addWeight({
|
||||
required double weight,
|
||||
}) async {
|
||||
Future<void> addWeight({required double weight}) async {
|
||||
try {
|
||||
return (await profileService.addWeight(weight: weight));
|
||||
} catch (e) {
|
||||
@@ -74,52 +66,32 @@ class ProfileRepository {
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<FeedBlogPostModel>> getBlogPostsByAuthorSlug({
|
||||
required String slug,
|
||||
}) async {
|
||||
Future<List<FeedBlogPostModel>> getBlogPostsByAuthorSlug({required String slug}) async {
|
||||
try {
|
||||
return (await profileService.getBlogPostByAuthorSlug(
|
||||
slug: slug,
|
||||
));
|
||||
return (await profileService.getBlogPostByAuthorSlug(slug: slug));
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<WeightModel>> getWeight({
|
||||
required String period,
|
||||
String? slug,
|
||||
}) async {
|
||||
Future<List<WeightModel>> getWeight({required String period, String? slug}) async {
|
||||
try {
|
||||
if (slug != null) {
|
||||
return (await profileService.getWeightBySlug(
|
||||
period: period,
|
||||
slug: slug,
|
||||
));
|
||||
return (await profileService.getWeightBySlug(period: period, slug: slug));
|
||||
} else {
|
||||
return (await profileService.getWeight(
|
||||
period: period,
|
||||
));
|
||||
return (await profileService.getWeight(period: period));
|
||||
}
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<CircumferenceModel>> getCircumferences({
|
||||
required String period,
|
||||
String? slug,
|
||||
}) async {
|
||||
Future<List<CircumferenceModel>> getCircumferences({required String period, String? slug}) async {
|
||||
try {
|
||||
if (slug != null) {
|
||||
return (await profileService.getCircumferencesBySlug(
|
||||
period: period,
|
||||
slug: slug,
|
||||
));
|
||||
return (await profileService.getCircumferencesBySlug(period: period, slug: slug));
|
||||
} else {
|
||||
return (await profileService.getCircumferences(
|
||||
period: period,
|
||||
));
|
||||
return (await profileService.getCircumferences(period: period));
|
||||
}
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
@@ -184,7 +156,8 @@ class ProfileRepository {
|
||||
|
||||
Future<String> getPassKey(String phone) async {
|
||||
return (jsonDecode(
|
||||
(await profileService.getPassKey(json: '{"route_name": "user_detailz.change-phone-verify", "route_params": {"phone": "$phone"}}'))))['key_is']!;
|
||||
(await profileService.getPassKey(json: '{"route_name": "user_detailz.change-phone-verify", "route_params": {"phone": "$phone"}}')),
|
||||
))['key_is']!;
|
||||
}
|
||||
|
||||
Future<String> getMyPhone() async {
|
||||
@@ -206,7 +179,7 @@ class ProfileRepository {
|
||||
|
||||
Future<void> deleteAccount() async {
|
||||
try {
|
||||
await profileService.deleteAccount();
|
||||
await profileService.deleteAccount();
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ abstract class ProfileService {
|
||||
@Path() required String period,
|
||||
});
|
||||
|
||||
@GET('/api/profile/measure/circumferences/{period}/{user}')
|
||||
@GET('/api/profile/measure/circumferences/{period}/{slug}')
|
||||
Future<List<CircumferenceModel>> getCircumferencesBySlug({
|
||||
@Path() required String period,
|
||||
@Path() required String slug,
|
||||
|
||||
@@ -27,48 +27,46 @@ class _GenderScreenState extends State<GenderScreen> {
|
||||
padding: const EdgeInsets.only(bottom: 80, top: 16, left: 16, right: 16),
|
||||
child: Column(
|
||||
children: [
|
||||
RadioListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
title: const Text('Мужской'),
|
||||
value: 'male',
|
||||
groupValue: currentValue,
|
||||
onChanged: (newValue) {
|
||||
final registrationCubit = context.read<RegistrationCubit>();
|
||||
registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(gender: 'male'));
|
||||
setState(() {
|
||||
currentValue = 'male';
|
||||
});
|
||||
},
|
||||
secondary: Image.asset(
|
||||
'assets/images/img_male.png',
|
||||
width: 40,
|
||||
height: 40,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Radio<String>(
|
||||
value: 'male',
|
||||
// ignore: deprecated_member_use
|
||||
groupValue: currentValue,
|
||||
// ignore: deprecated_member_use
|
||||
onChanged: (newValue) {
|
||||
final registrationCubit = context.read<RegistrationCubit>();
|
||||
registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(gender: 'male'));
|
||||
setState(() {
|
||||
currentValue = 'male';
|
||||
});
|
||||
},
|
||||
),
|
||||
Expanded(
|
||||
child: Row(children: [Image.asset('assets/images/img_male.png', width: 40, height: 40), const SizedBox(width: 8), const Text('Мужской')]),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
RadioListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
title: const Text('Женский'),
|
||||
value: 'female',
|
||||
groupValue: currentValue,
|
||||
onChanged: (newValue) {
|
||||
final registrationCubit = context.read<RegistrationCubit>();
|
||||
registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(gender: 'female'));
|
||||
setState(() {
|
||||
currentValue = 'female';
|
||||
});
|
||||
},
|
||||
secondary: Image.asset(
|
||||
'assets/images/img_female.png',
|
||||
width: 40,
|
||||
height: 40,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Radio<String>(
|
||||
value: 'female',
|
||||
// ignore: deprecated_member_use
|
||||
groupValue: currentValue,
|
||||
// ignore: deprecated_member_use
|
||||
onChanged: (newValue) {
|
||||
final registrationCubit = context.read<RegistrationCubit>();
|
||||
registrationCubit.updateSheet(registrationCubit.state.sheet.copyWith(gender: 'female'));
|
||||
setState(() {
|
||||
currentValue = 'female';
|
||||
});
|
||||
},
|
||||
),
|
||||
Expanded(
|
||||
child: Row(children: [Image.asset('assets/images/img_female.png', width: 40, height: 40), const SizedBox(width: 8), const Text('Женский')]),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import 'dart:async';
|
||||
|
||||
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/toasts.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
|
||||
import 'package:eatvio_app/features/registration/presentation/bloc/verify_email_cubit/verify_email_cubit.dart';
|
||||
import 'package:eatvio_app/features/registration/presentation/bloc/verify_email_cubit/verify_email_state.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -18,11 +23,14 @@ class _VerifyEmailScreenState extends State<VerifyEmailScreen> {
|
||||
final List<TextEditingController> _controllers = List.generate(4, (_) => TextEditingController());
|
||||
String email = '';
|
||||
late final GoRouter goRouter;
|
||||
|
||||
late Timer _timer;
|
||||
int _secondsRemaining = 60;
|
||||
bool _canSendAgain = false;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
goRouter = GoRouter.of(context);
|
||||
goRouter = GoRouter.of(context);
|
||||
_startTimer();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -36,6 +44,23 @@ class _VerifyEmailScreenState extends State<VerifyEmailScreen> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _startTimer() {
|
||||
setState(() {
|
||||
_canSendAgain = false;
|
||||
_secondsRemaining = 60;
|
||||
});
|
||||
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||
setState(() {
|
||||
if (_secondsRemaining > 0) {
|
||||
_secondsRemaining--;
|
||||
} else {
|
||||
_canSendAgain = true;
|
||||
_timer.cancel();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void _checkAndSubmitCode(BuildContext context) {
|
||||
final code = _controllers.map((c) => c.text).join();
|
||||
if (code.length == 4) {
|
||||
@@ -74,18 +99,25 @@ class _VerifyEmailScreenState extends State<VerifyEmailScreen> {
|
||||
children: [
|
||||
Text("Код отправлен на почту\n$email", textAlign: TextAlign.center),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: List.generate(4, (index) => _buildCodeField(context, index)),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
const Text("Запросить код повторно", style: TextStyle(color: Colors.grey)),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
context.read<VerifyEmailCubit>().sendEmailCode();
|
||||
Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: List.generate(4, (index) => _buildCodeField(context, index))),
|
||||
const SizedBox(height: 40),
|
||||
CustomOutlinedButton(
|
||||
text: 'Запросить код повторно',
|
||||
height: 52,
|
||||
isDisabled: !_canSendAgain,
|
||||
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
|
||||
buttonStyle: ButtonStyle(
|
||||
side: const WidgetStatePropertyAll(BorderSide.none),
|
||||
backgroundColor: WidgetStatePropertyAll(_canSendAgain ? appTheme.blueA400 : appTheme.gray),
|
||||
),
|
||||
onPressed: () async {
|
||||
await context.read<VerifyEmailCubit>().sendEmailCode();
|
||||
_startTimer();
|
||||
},
|
||||
child: const Text("Не приходит код?"),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
if (!_canSendAgain)
|
||||
Text("Зпросить код повторно можно через $_secondsRemaining с.", style: TextStyles.textSMedium.copyWith(color: appTheme.gray)),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -7,10 +7,7 @@ import 'package:go_router/go_router.dart';
|
||||
class PhysicalActivityScreen extends StatefulWidget {
|
||||
final SettingsEntity settingsEntity;
|
||||
|
||||
const PhysicalActivityScreen({
|
||||
super.key,
|
||||
required this.settingsEntity,
|
||||
});
|
||||
const PhysicalActivityScreen({super.key, required this.settingsEntity});
|
||||
|
||||
@override
|
||||
State<PhysicalActivityScreen> createState() => _PhysicalActivityScreenState();
|
||||
@@ -46,69 +43,108 @@ class _PhysicalActivityScreenState extends State<PhysicalActivityScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Физическая нагрузка'),
|
||||
),
|
||||
appBar: AppBar(title: const Text('Физическая нагрузка')),
|
||||
bottomSheet: _saveButton(),
|
||||
body: SingleChildScrollView(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
padding: const EdgeInsets.only(top: 16, bottom: 80),
|
||||
child: Column(
|
||||
children: [
|
||||
RadioListTile<PhysicalActivity>(
|
||||
contentPadding: const EdgeInsets.only(left: 8, right: 16),
|
||||
title: const Text('1,2 — минимальный (сидячая работа, отсутствие физических нагрузок);'),
|
||||
value: PhysicalActivity.minimum,
|
||||
groupValue: _physicalActivity,
|
||||
onChanged: (PhysicalActivity? value) {
|
||||
setState(() {
|
||||
_physicalActivity = value;
|
||||
});
|
||||
},
|
||||
Row(
|
||||
children: [
|
||||
Radio<PhysicalActivity>(
|
||||
value: PhysicalActivity.minimum,
|
||||
// ignore: deprecated_member_use
|
||||
groupValue: _physicalActivity,
|
||||
// ignore: deprecated_member_use
|
||||
onChanged: (PhysicalActivity? value) {
|
||||
setState(() {
|
||||
_physicalActivity = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
const Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(left: 8, right: 16),
|
||||
child: Text('1,2 — минимальный (сидячая работа, отсутствие физических нагрузок);'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
RadioListTile<PhysicalActivity>(
|
||||
contentPadding: const EdgeInsets.only(left: 8, right: 16),
|
||||
title: const Text('1,375 — низкий (тренировки не менее 20 мин 1–3 раза в неделю);'),
|
||||
value: PhysicalActivity.low,
|
||||
groupValue: _physicalActivity,
|
||||
onChanged: (PhysicalActivity? value) {
|
||||
setState(() {
|
||||
_physicalActivity = value;
|
||||
});
|
||||
},
|
||||
Row(
|
||||
children: [
|
||||
Radio<PhysicalActivity>(
|
||||
value: PhysicalActivity.low,
|
||||
// ignore: deprecated_member_use
|
||||
groupValue: _physicalActivity,
|
||||
// ignore: deprecated_member_use
|
||||
onChanged: (PhysicalActivity? value) {
|
||||
setState(() {
|
||||
_physicalActivity = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
const Expanded(
|
||||
child: Padding(padding: EdgeInsets.only(left: 8, right: 16), child: Text('1,375 — низкий (тренировки не менее 20 мин 1–3 раза в неделю);')),
|
||||
),
|
||||
],
|
||||
),
|
||||
RadioListTile<PhysicalActivity>(
|
||||
contentPadding: const EdgeInsets.only(left: 8, right: 16),
|
||||
title: const Text('1,55 — умеренный (тренировки 30–60 мин 3–4 раза в неделю);'),
|
||||
value: PhysicalActivity.medium,
|
||||
groupValue: _physicalActivity,
|
||||
onChanged: (PhysicalActivity? value) {
|
||||
setState(() {
|
||||
_physicalActivity = value;
|
||||
});
|
||||
},
|
||||
Row(
|
||||
children: [
|
||||
Radio<PhysicalActivity>(
|
||||
value: PhysicalActivity.medium,
|
||||
// ignore: deprecated_member_use
|
||||
groupValue: _physicalActivity,
|
||||
// ignore: deprecated_member_use
|
||||
onChanged: (PhysicalActivity? value) {
|
||||
setState(() {
|
||||
_physicalActivity = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
const Expanded(
|
||||
child: Padding(padding: EdgeInsets.only(left: 8, right: 16), child: Text('1,55 — умеренный (тренировки 30–60 мин 3–4 раза в неделю);')),
|
||||
),
|
||||
],
|
||||
),
|
||||
RadioListTile<PhysicalActivity>(
|
||||
contentPadding: const EdgeInsets.only(left: 8, right: 16),
|
||||
title: const Text('1,7 — высокий (тренировки 30–60 мин 5–7 раза в неделю; тяжёлая физическая работа);'),
|
||||
value: PhysicalActivity.high,
|
||||
groupValue: _physicalActivity,
|
||||
onChanged: (PhysicalActivity? value) {
|
||||
setState(() {
|
||||
_physicalActivity = value;
|
||||
});
|
||||
},
|
||||
Row(
|
||||
children: [
|
||||
Radio<PhysicalActivity>(
|
||||
value: PhysicalActivity.high,
|
||||
// ignore: deprecated_member_use
|
||||
groupValue: _physicalActivity,
|
||||
// ignore: deprecated_member_use
|
||||
onChanged: (PhysicalActivity? value) {
|
||||
setState(() {
|
||||
_physicalActivity = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
const Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(left: 8, right: 16),
|
||||
child: Text('1,7 — высокий (тренировки 30–60 мин 5–7 раза в неделю; тяжёлая физическая работа);'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
RadioListTile<PhysicalActivity>(
|
||||
contentPadding: const EdgeInsets.only(left: 8, right: 16),
|
||||
title: const Text('1,9 — экстремальный (несколько интенсивных тренировок в день'),
|
||||
value: PhysicalActivity.extreme,
|
||||
groupValue: _physicalActivity,
|
||||
onChanged: (PhysicalActivity? value) {
|
||||
setState(() {
|
||||
_physicalActivity = value;
|
||||
});
|
||||
},
|
||||
Row(
|
||||
children: [
|
||||
Radio<PhysicalActivity>(
|
||||
value: PhysicalActivity.extreme,
|
||||
// ignore: deprecated_member_use
|
||||
groupValue: _physicalActivity,
|
||||
// ignore: deprecated_member_use
|
||||
onChanged: (PhysicalActivity? value) {
|
||||
setState(() {
|
||||
_physicalActivity = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
const Expanded(
|
||||
child: Padding(padding: EdgeInsets.only(left: 8, right: 16), child: Text('1,9 — экстремальный (несколько интенсивных тренировок в день')),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -141,8 +177,8 @@ class _PhysicalActivityScreenState extends State<PhysicalActivityScreen> {
|
||||
}
|
||||
widget.settingsEntity.settingsCubit.updateProfileDetails(
|
||||
profileDetailsModel: (widget.settingsEntity.settingsCubit.state as SettingsStateLoaded).profileDetails.copyWith(
|
||||
activityCoefficient: activityCoefficient,
|
||||
),
|
||||
activityCoefficient: activityCoefficient,
|
||||
),
|
||||
);
|
||||
GoRouter.of(context).pop();
|
||||
},
|
||||
@@ -150,19 +186,11 @@ class _PhysicalActivityScreenState extends State<PhysicalActivityScreen> {
|
||||
child: Ink(
|
||||
height: 52,
|
||||
width: MediaQuery.of(context).size.width - 32,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: appTheme.blueA400,
|
||||
),
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(20), color: appTheme.blueA400),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'Сохранить',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
height: 1,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 18,
|
||||
),
|
||||
style: TextStyle(color: Colors.white, height: 1, fontWeight: FontWeight.w600, fontSize: 18),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -71,15 +71,24 @@ class SupportScreen extends StatelessWidget {
|
||||
const SizedBox(height: 12),
|
||||
if (!hidePlans) ...[
|
||||
InkWell(
|
||||
onTap: () async => await launchUrl(Uri.parse('$baseUrl/docs/privacy.pdf')),
|
||||
onTap: () async => await launchUrl(Uri.parse('$baseUrl/docs/public_offer.pdf')),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||
child: Text('Политика конфиденциальности', style: TextStyle(fontSize: 16)),
|
||||
child: Text('Публичная офёрта', style: TextStyle(fontSize: 16)),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
InkWell(
|
||||
onTap: () async => await launchUrl(Uri.parse('$baseUrl/docs/privacy.pdf')),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||
child: Text('Политика конфиденциальности', style: TextStyle(fontSize: 16)),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
InkWell(
|
||||
onTap: () async => await launchUrl(Uri.parse('$baseUrl/company-details')),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
|
||||
47
pubspec.yaml
47
pubspec.yaml
@@ -1,6 +1,6 @@
|
||||
name: eatvio_app
|
||||
description: A new Flutter project.
|
||||
version: 1.2.9+69
|
||||
version: 1.2.10+70
|
||||
publish_to: 'none'
|
||||
|
||||
environment:
|
||||
@@ -13,11 +13,6 @@ dependencies:
|
||||
flutter_localizations:
|
||||
sdk: flutter
|
||||
|
||||
flutter_secure_storage:
|
||||
git:
|
||||
url: https://github.com/sherlockvn/flutter_secure_storage.git
|
||||
ref: remove-old-encrypt-algorithm
|
||||
path: flutter_secure_storage
|
||||
flutter_bloc: ^9.1.1
|
||||
cached_network_image: ^3.4.1
|
||||
flutter_svg: ^2.2.0
|
||||
@@ -27,28 +22,28 @@ dependencies:
|
||||
validators: ^3.0.0
|
||||
path_provider: ^2.1.5
|
||||
carousel_slider_plus: ^7.1.1
|
||||
flutter_form_builder: ^10.1.0
|
||||
image_picker: ^1.1.2
|
||||
flutter_form_builder: ^10.2.0
|
||||
image_picker: ^1.2.0
|
||||
flutter_typeahead: ^5.2.0
|
||||
go_router: ^16.0.0
|
||||
go_router: ^16.1.0
|
||||
keyboard_dismisser: ^3.0.0
|
||||
retrofit: ^4.7.0
|
||||
get_it: ^8.1.0
|
||||
dio: ^5.8.0+1
|
||||
retrofit: ^4.7.1
|
||||
get_it: ^8.2.0
|
||||
dio: ^5.9.0
|
||||
dart_pusher_channels: ^1.2.3
|
||||
photo_view: ^0.15.0
|
||||
dismissible_page: ^1.0.2
|
||||
url_launcher: ^6.3.2
|
||||
easy_debounce: ^2.0.3
|
||||
badges: ^3.1.2
|
||||
google_fonts: ^6.2.1
|
||||
syncfusion_flutter_charts: ^30.1.42
|
||||
syncfusion_flutter_gauges: ^30.1.42
|
||||
google_fonts: ^6.3.0
|
||||
syncfusion_flutter_charts: ^30.2.5
|
||||
syncfusion_flutter_gauges: ^30.2.5
|
||||
table_calendar: ^3.2.0
|
||||
flutter_keyboard_visibility: ^6.0.0
|
||||
share_plus: ^11.0.0
|
||||
share_plus: ^11.1.0
|
||||
flutter_html: ^3.0.0
|
||||
file_picker: ^10.2.0
|
||||
file_picker: ^10.3.1
|
||||
audioplayers: ^6.5.0
|
||||
intl: ^0.20.2
|
||||
mask_text_input_formatter: ^2.9.0
|
||||
@@ -59,31 +54,31 @@ dependencies:
|
||||
flutter_image_compress: ^2.4.0
|
||||
image: ^4.5.4
|
||||
dotted_border: ^3.1.0
|
||||
http: ^1.4.0
|
||||
http: ^1.5.0
|
||||
flutter_native_splash: ^2.4.6
|
||||
webview_flutter: ^4.13.0
|
||||
sentry_flutter: ^9.5.0
|
||||
connectivity_plus: ^6.1.4
|
||||
sentry_flutter: ^9.6.0
|
||||
connectivity_plus: ^6.1.5
|
||||
visibility_detector: ^0.4.0+2
|
||||
firebase_core: ^3.15.2
|
||||
firebase_messaging: ^15.2.10
|
||||
firebase_core: ^4.0.0
|
||||
firebase_messaging: ^16.0.0
|
||||
http_parser: ^4.1.2
|
||||
path: ^1.9.1
|
||||
collection: ^1.19.1
|
||||
shared_preferences: ^2.5.3
|
||||
version: ^3.0.2
|
||||
package_info_plus: ^8.3.0
|
||||
package_info_plus: ^8.3.1
|
||||
device_info_plus: ^11.5.0
|
||||
permission_handler: ^12.0.1
|
||||
qr_code_scanner_plus: ^2.0.10+1
|
||||
flutter_dotenv: ^5.1.0
|
||||
flutter_dotenv: ^5.2.1
|
||||
uuid: ^4.5.1
|
||||
|
||||
dev_dependencies:
|
||||
build_runner: ^2.6.0
|
||||
build_runner: ^2.7.0
|
||||
freezed: ^3.2.0
|
||||
json_serializable: ^6.10.0
|
||||
retrofit_generator: ^10.0.1
|
||||
retrofit_generator: ^10.0.2
|
||||
mockito: ^5.5.0
|
||||
|
||||
flutter_test:
|
||||
|
||||
Reference in New Issue
Block a user