fix profile
This commit is contained in:
@@ -39,6 +39,9 @@ class ApiService {
|
||||
static const String baseUrl = "https://api.behappybel.by/api/v1";
|
||||
static const String fileBaseUrl = "https://api.behappybel.by/";
|
||||
|
||||
/*static const String baseUrl = "https://sharing-api.sparkit.by/api/v1";
|
||||
static const String fileBaseUrl = "https://sharing-api.sparkit.by";
|
||||
*/
|
||||
final SecurityService _securityService;
|
||||
final Dio _dio;
|
||||
|
||||
@@ -172,6 +175,53 @@ class ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteProfile() async {
|
||||
try {
|
||||
final response = await _dio.delete(
|
||||
"$baseUrl/client/me",
|
||||
options: await _getAuthOptions(),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = response.data;
|
||||
final profileData = data["profile"];
|
||||
if (profileData == null) return null;
|
||||
|
||||
String? parsedDate;
|
||||
if (profileData["dob"] != null) {
|
||||
try {
|
||||
parsedDate = DateFormat(
|
||||
'dd.MM.yyyy',
|
||||
).format(DateTime.parse(profileData["dob"]));
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
final int? avatarId = profileData["avatarId"];
|
||||
String? avatarUrl;
|
||||
|
||||
if (avatarId != null && profileData["avatar"] != null) {
|
||||
final String? avatarPath = profileData["avatar"]["path"];
|
||||
if (avatarPath != null && avatarPath.isNotEmpty) {
|
||||
avatarUrl = Uri.parse(fileBaseUrl).resolve(avatarPath).toString();
|
||||
}
|
||||
}
|
||||
|
||||
dynamic balanceRaw = profileData["balance"];
|
||||
double? balance;
|
||||
|
||||
if (balanceRaw is num) {
|
||||
balance = balanceRaw.toDouble();
|
||||
} else if (balanceRaw is String) {
|
||||
balance = double.tryParse(balanceRaw);
|
||||
}
|
||||
|
||||
}
|
||||
return null;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<PaymentCard>> getPaymentCards() async {
|
||||
final response = await _dio.get(
|
||||
"$baseUrl/client/me",
|
||||
|
||||
@@ -27,6 +27,11 @@ class UserProfileRepositoryImpl implements UserProfileRepository {
|
||||
return await _apiService.getProfile() ?? _cachedProfile;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> deleteProfile() async {
|
||||
return await _apiService.deleteProfile();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<UserProfile?> updateProfile(UserProfile profile) async {
|
||||
//await Future.delayed(const Duration(milliseconds: 300));
|
||||
|
||||
@@ -17,6 +17,7 @@ import 'package:be_happy/domain/repositories/scooter_repository.dart';
|
||||
import 'package:be_happy/domain/repositories/zone_repository.dart';
|
||||
import 'package:be_happy/domain/service/security_service.dart';
|
||||
import 'package:be_happy/domain/usecase/add_payment_card_usecase.dart'; // ← новый
|
||||
import 'package:be_happy/domain/usecase/delete_profile_usecase.dart';
|
||||
import 'package:be_happy/domain/usecase/get_certificates_usecase.dart';
|
||||
import 'package:be_happy/domain/usecase/get_scooter_order_route_history_usecase.dart';
|
||||
import 'package:be_happy/domain/usecase/is_pin_set_usecase.dart';
|
||||
@@ -54,6 +55,7 @@ import 'package:be_happy/domain/usecase/finish_ride_usecase.dart';
|
||||
import 'package:be_happy/domain/usecase/pause_ride_usecase.dart';
|
||||
import 'package:be_happy/domain/usecase/resume_ride_usecase.dart';
|
||||
import 'package:be_happy/domain/usecase/verify_pin_usecase.dart';
|
||||
import 'package:be_happy/presentation/event/profile_event.dart';
|
||||
import 'package:be_happy/presentation/viewmodel/active_ride_bloc.dart';
|
||||
import 'package:be_happy/presentation/viewmodel/add_card_bloc.dart'; // ← новый
|
||||
import 'package:be_happy/presentation/viewmodel/current_rides_bloc.dart';
|
||||
@@ -205,6 +207,8 @@ Future<void> setupDependencies() async {
|
||||
|
||||
getIt.registerSingleton<GetProfileUseCase>(GetProfileUseCase(getIt()));
|
||||
|
||||
getIt.registerSingleton<DeleteProfileUsecase>(DeleteProfileUsecase(getIt(), getIt(), getIt()));
|
||||
|
||||
getIt.registerSingleton<UpdateProfileUseCase>(UpdateProfileUseCase(getIt()));
|
||||
|
||||
getIt.registerSingleton<UploadProfilePhotoUsecase>(
|
||||
@@ -319,7 +323,7 @@ Future<void> setupDependencies() async {
|
||||
);
|
||||
|
||||
getIt.registerLazySingleton<ProfileBloc>(
|
||||
() => ProfileBloc(getIt(), getIt(), getIt()),
|
||||
() => ProfileBloc(getIt(), getIt(), getIt(), getIt(), getIt(), getIt()),
|
||||
);
|
||||
|
||||
getIt.registerFactory<EditProfileBloc>(
|
||||
|
||||
@@ -2,6 +2,7 @@ class Tariff {
|
||||
final int id;
|
||||
final String title;
|
||||
final String description;
|
||||
final String descriptionJson;
|
||||
final bool isActive;
|
||||
final String currency;
|
||||
final double holdPrice; // Старт / бронь
|
||||
@@ -15,6 +16,7 @@ class Tariff {
|
||||
required this.id,
|
||||
required this.title,
|
||||
required this.description,
|
||||
required this.descriptionJson,
|
||||
required this.isActive,
|
||||
required this.currency,
|
||||
required this.holdPrice,
|
||||
@@ -33,6 +35,7 @@ class Tariff {
|
||||
id: json['id'] ?? 0,
|
||||
title: json['title'] ?? 'Unknown',
|
||||
description: json['description'] ?? '',
|
||||
descriptionJson: json['descriptionJson'] ?? '',
|
||||
isActive: json['isActive'] ?? false,
|
||||
currency: currency['currency'] ?? 'BYN',
|
||||
holdPrice: (planPrice['hold'] as num?)?.toDouble() ?? 0.0,
|
||||
|
||||
@@ -5,6 +5,7 @@ import '../entities/user_profile.dart';
|
||||
|
||||
abstract class UserProfileRepository {
|
||||
Future<UserProfile> getProfile();
|
||||
Future<void> deleteProfile();
|
||||
Future<UserProfile?> updateProfile(UserProfile profile);
|
||||
Future<int?> uploadProfilePhoto(File imageFile);
|
||||
Future<UserCheckFlags?> checkUser();
|
||||
|
||||
21
lib/domain/usecase/delete_profile_usecase.dart
Normal file
21
lib/domain/usecase/delete_profile_usecase.dart
Normal file
@@ -0,0 +1,21 @@
|
||||
import '../entities/user_profile.dart';
|
||||
import '../repositories/auth_repository.dart';
|
||||
import '../repositories/pin_repository.dart';
|
||||
import '../repositories/profile_repository.dart';
|
||||
|
||||
class DeleteProfileUsecase {
|
||||
final UserProfileRepository repository;
|
||||
final PinRepository _pinRepository;
|
||||
final AuthRepository _authRepository;
|
||||
|
||||
|
||||
|
||||
DeleteProfileUsecase(this.repository, this._pinRepository, this._authRepository);
|
||||
|
||||
Future<void> call() {
|
||||
_pinRepository.removePin();
|
||||
repository.deleteProfile();
|
||||
return _authRepository.logout();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart'; // 🔹 1. Добавлен импорт
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:bot_toast/bot_toast.dart';
|
||||
import 'package:be_happy/presentation/event/edit_profile_event.dart';
|
||||
import 'package:be_happy/presentation/event/profile_event.dart';
|
||||
@@ -69,6 +70,14 @@ class MyApp extends StatelessWidget {
|
||||
title: 'BeHappy',
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: ThemeData.dark(),
|
||||
localizationsDelegates: const [
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: const [
|
||||
Locale('ru', 'RU'),
|
||||
],
|
||||
builder: BotToastInit(),
|
||||
routerConfig: appRouter.router,
|
||||
),
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class DeleteAccountDialog extends StatelessWidget {
|
||||
const DeleteAccountDialog({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Dialog(
|
||||
backgroundColor: Colors.transparent,
|
||||
insetPadding: const EdgeInsets.symmetric(horizontal: 40),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(24),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF2E3253).withOpacity(0.95),
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text(
|
||||
"Удалить\nучётную запись?",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.w600,
|
||||
height: 1.2,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
"Это действие необратимо. Все ваши\nданные будут удалены безвозвратно",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Colors.white70,
|
||||
fontSize: 14,
|
||||
height: 1.4,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 52,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(26),
|
||||
gradient: const LinearGradient(
|
||||
colors: [Color(0xFFFF8E8E), Color(0xFFFE5F86)],
|
||||
),
|
||||
),
|
||||
child: ElevatedButton(
|
||||
onPressed: () => Navigator.pop(context, true),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.transparent,
|
||||
shadowColor: Colors.transparent,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(26),
|
||||
),
|
||||
),
|
||||
child: const Text(
|
||||
"Удалить",
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: 52,
|
||||
child: ElevatedButton(
|
||||
onPressed: () => Navigator.pop(context, false),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF0D1024),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(26),
|
||||
),
|
||||
),
|
||||
child: const Text(
|
||||
"Отмена",
|
||||
style: TextStyle(color: Colors.white, fontSize: 16),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ import 'package:be_happy/domain/entities/tariff.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
import '../content_parser.dart';
|
||||
|
||||
class TariffInfoSheet extends StatefulWidget {
|
||||
final Tariff tariff;
|
||||
final bool isInsurance;
|
||||
@@ -42,7 +44,6 @@ class _TariffInfoSheetState extends State<TariffInfoSheet> {
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
// Полоска сверху (Handle)
|
||||
const SizedBox(height: 12),
|
||||
Container(
|
||||
width: 40,
|
||||
@@ -81,9 +82,9 @@ class _TariffInfoSheetState extends State<TariffInfoSheet> {
|
||||
const SizedBox(height: 30),
|
||||
|
||||
// Таблица цен
|
||||
_buildPriceRow('Старт поездки', '${widget.tariff.startPrice} BYN'),
|
||||
_buildPriceRow('Последующая минута', '${widget.tariff.drivePrice} BYN'),
|
||||
_buildPriceRow('Пауза', '${widget.tariff.pausePrice} BYN/мин'),
|
||||
_buildPriceRow('Старт поездки', '${widget.tariff.startPrice} руб.'),
|
||||
_buildPriceRow('Последующая минута', '${widget.tariff.drivePrice} руб.'),
|
||||
_buildPriceRow('Пауза', '${widget.tariff.pausePrice} руб./мин'),
|
||||
_buildPriceRow('КЕШБЭК', '${widget.tariff.cashback * 100}%', isAccent: true),
|
||||
|
||||
const Divider(color: Colors.white24, height: 40),
|
||||
@@ -98,7 +99,7 @@ class _TariffInfoSheetState extends State<TariffInfoSheet> {
|
||||
Image.asset('assets/icons/info_icon.png', width: 18, height: 18),
|
||||
const Spacer(),
|
||||
Text(
|
||||
'${widget.tariff.insurance} BYN',
|
||||
'${widget.tariff.insurance} руб.',
|
||||
style: TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
@@ -118,10 +119,14 @@ class _TariffInfoSheetState extends State<TariffInfoSheet> {
|
||||
|
||||
const Divider(color: Colors.white24, height: 40),
|
||||
|
||||
_buildInfoBullet('Оплата страховки осуществляется только по банковской карте отдельным платежом'),
|
||||
_buildInfoBullet('В режиме паузы время тарифа приостанавливается'),
|
||||
_buildInfoBullet('При старте заказа будет заблокирована сумма в размере 7 рублей для проверки платежеспособности. Сумма разблокируется по факту списания средств за поездку.'),
|
||||
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: ContentParser.parseContent(
|
||||
textJson: widget.tariff.description,
|
||||
text: widget.tariff.descriptionJson,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -281,7 +281,7 @@ class _TariffSheetState extends State<TariffSheet> {
|
||||
subtitle: 'Старт поездки',
|
||||
details: [
|
||||
'Далее ${tariff.drivePrice.toStringAsFixed(2)} ${tariff.currency}/мин.',
|
||||
'Минута на паузе ${tariff.pausePrice.toStringAsFixed(0)} ${tariff.currency}',
|
||||
'Минута на паузе ${tariff.pausePrice.toStringAsFixed(2)} ${tariff.currency}',
|
||||
],
|
||||
isSelected: _selectedTariffIndex == index,
|
||||
isInsurance: state.isInsurance,
|
||||
|
||||
@@ -8,6 +8,8 @@ class ProfileStarted extends ProfileEvent {}
|
||||
|
||||
class ProfileUpdated extends ProfileEvent {}
|
||||
|
||||
class DeleteProfilePressed extends ProfileEvent {}
|
||||
|
||||
class ProfilePhotoUpdated extends ProfileEvent{
|
||||
final File imageFile;
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ class _EditProfileScreenState extends State<EditProfileScreen> {
|
||||
initialDate: _selectedBirthDate ?? DateTime.now(),
|
||||
firstDate: DateTime(DateTime.now().year - 100),
|
||||
lastDate: DateTime.now(),
|
||||
locale: const Locale('ru', 'RU'),
|
||||
);
|
||||
|
||||
if (picked != null && picked != _selectedBirthDate) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import '../../core/app_colors.dart';
|
||||
import '../../domain/entities/user_profile.dart';
|
||||
import '../components/custom_app_bar.dart';
|
||||
import '../components/gradient_button.dart';
|
||||
import '../components/dialog/delete_account_dialog.dart';
|
||||
import '../viewmodel/profile_bloc.dart';
|
||||
import 'edit_profile_screen.dart';
|
||||
|
||||
@@ -43,7 +44,19 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
}
|
||||
|
||||
Future<void> _openEditProfile(UserProfile profile) async {
|
||||
context.go("/home/profile/edit");
|
||||
context.go("/home/profile/edit");
|
||||
}
|
||||
|
||||
Future<void> _confirmDeleteAccount(BuildContext context) async {
|
||||
final confirmed = await showDialog<bool>(
|
||||
context: context,
|
||||
barrierColor: Colors.black.withOpacity(0.6),
|
||||
builder: (dialogContext) => const DeleteAccountDialog(),
|
||||
);
|
||||
|
||||
if (confirmed == true && context.mounted) {
|
||||
context.read<ProfileBloc>().add(DeleteProfilePressed());
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -136,12 +149,17 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
onEditTap: () => context.go("/home/profile/edit"),
|
||||
),
|
||||
|
||||
// const SizedBox(height: 24),
|
||||
// _SettingsBlock(
|
||||
// notificationsEnabled: notificationsEnabled,
|
||||
// onNotificationsChanged: (v) =>
|
||||
// setState(() => notificationsEnabled = v),
|
||||
// ),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: GradientButton(
|
||||
text: 'Удалить учётную запись',
|
||||
onTap: () => _confirmDeleteAccount(context),
|
||||
showArrows: true,
|
||||
height: 56,
|
||||
width: double.infinity,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -370,4 +388,4 @@ class _SettingsBlock extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,38 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:be_happy/domain/usecase/delete_profile_usecase.dart';
|
||||
import 'package:be_happy/domain/usecase/upload_profile_photo_usecase.dart';
|
||||
import 'package:be_happy/presentation/viewmodel/splash_bloc.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../../domain/entities/user_profile.dart';
|
||||
import '../../domain/usecase/get_profile_usecase.dart';
|
||||
import '../../domain/usecase/logout_usecase.dart';
|
||||
import '../../domain/usecase/update_profile_usecase.dart';
|
||||
import '../event/profile_event.dart';
|
||||
import '../event/spalsh_event.dart';
|
||||
import '../state/profile_state.dart';
|
||||
|
||||
class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
|
||||
final GetProfileUseCase getProfileUseCase;
|
||||
final UploadProfilePhotoUsecase uploadProfilePhotoUsecase;
|
||||
final UpdateProfileUseCase updateProfileUseCase;
|
||||
final DeleteProfileUsecase deleteProfileUsecase;
|
||||
final LogoutUseCase logoutUseCase;
|
||||
final SplashBloc splashBloc;
|
||||
|
||||
|
||||
ProfileBloc(this.getProfileUseCase,
|
||||
this.uploadProfilePhotoUsecase,
|
||||
this.updateProfileUseCase)
|
||||
this.updateProfileUseCase,
|
||||
this.deleteProfileUsecase,
|
||||
this.logoutUseCase,
|
||||
this.splashBloc)
|
||||
: super(ProfileState.initial()) {
|
||||
on<ProfileStarted>(_onStarted);
|
||||
on<ProfileUpdated>(_onUpdated);
|
||||
on<ProfilePhotoUpdated>(_onPhotoUploaded);
|
||||
on<DeleteProfilePressed>(_onDeleteProfilePressed);
|
||||
}
|
||||
|
||||
Future<void> _onStarted(
|
||||
@@ -55,7 +68,6 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
|
||||
final avatarId = await uploadProfilePhotoUsecase(event.imageFile);
|
||||
|
||||
if (avatarId != null) {
|
||||
// Отправляем PATCH запрос с новым avatarId
|
||||
await updateProfileUseCase(UserProfile(
|
||||
name: '',
|
||||
birthDate: '',
|
||||
@@ -72,4 +84,14 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
|
||||
emit(state.copyWith(isLoading: false, error: "Ошибка загрузки: ${e.toString()}"));
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> _onDeleteProfilePressed(DeleteProfilePressed event, Emitter<ProfileState> emit) async {
|
||||
try {
|
||||
|
||||
await deleteProfileUsecase();
|
||||
splashBloc.add(AuthLogoutRequested());
|
||||
} catch (e) {
|
||||
emit(state.copyWith(isLoading: false, error: "Ошибка удаления профиля: ${e.toString()}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,6 +294,11 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
flutter_localizations:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_native_splash:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@@ -540,10 +545,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: intl
|
||||
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
|
||||
sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.19.0"
|
||||
version: "0.20.2"
|
||||
jni:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -2,7 +2,7 @@ name: be_happy
|
||||
description: ""
|
||||
publish_to: 'none'
|
||||
|
||||
version: 1.0.0+22
|
||||
version: 1.0.0+23
|
||||
|
||||
environment:
|
||||
sdk: ^3.8.1
|
||||
@@ -10,6 +10,8 @@ environment:
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
flutter_localizations:
|
||||
sdk: flutter
|
||||
cupertino_icons: ^1.0.8
|
||||
flutter_secure_storage: ^9.2.4
|
||||
shared_preferences: ^2.5.3
|
||||
@@ -21,7 +23,7 @@ dependencies:
|
||||
path: ^1.9.0
|
||||
async: ^2.11.0
|
||||
mime: ^1.0.5
|
||||
intl: ^0.19.0
|
||||
intl: ^0.20.2
|
||||
url_launcher: ^6.2.5
|
||||
go_router: ^14.0.0
|
||||
android_id: ^0.4.0
|
||||
|
||||
Reference in New Issue
Block a user