fix: stabilize auth and home error flows

This commit is contained in:
Artem Kokos
2026-04-27 23:11:45 +07:00
parent c2d7ce5bdc
commit eed04e9122
5 changed files with 247 additions and 41 deletions

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../app/error_message.dart';
import '../models/home_config.dart';
import '../providers/providers.dart';
import '../services/api_client.dart';
@@ -321,7 +322,7 @@ class _HomeEditScreenState extends ConsumerState<HomeEditScreen> {
final currentHome = ref.read(currentHomeProvider);
if (currentHome?.id == home.id) {
await ref.read(currentHomeProvider.notifier).switchTo(home);
await ref.read(currentHomeProvider.notifier).select(home);
}
// Синхронизировать фоновый таск с новыми настройками
@@ -331,9 +332,13 @@ class _HomeEditScreenState extends ConsumerState<HomeEditScreen> {
if (mounted) Navigator.of(context).pop();
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Не удалось проверить дом: $e')));
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Не удалось сохранить дом: ${describeLoadError(e)}',
),
),
);
}
} finally {
if (mounted) setState(() => _saving = false);

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../app/error_message.dart';
import '../models/home_config.dart';
import '../providers/providers.dart';
import '../widgets/build_info_text.dart';
@@ -17,6 +18,8 @@ class HomesScreen extends ConsumerStatefulWidget {
class _HomesScreenState extends ConsumerState<HomesScreen> {
late final UserLocationNotifier _userLocationNotifier;
String? _switchingHomeId;
String? _deletingHomeId;
@override
void initState() {
@@ -53,6 +56,9 @@ class _HomesScreenState extends ConsumerState<HomesScreen> {
itemBuilder: (context, index) {
final home = homes[index];
final isActive = currentHome?.id == home.id;
final isSwitching = _switchingHomeId == home.id;
final isDeleting = _deletingHomeId == home.id;
final isBusy = isSwitching || isDeleting;
final distKm = location.distanceToKm(
home.latitude,
home.longitude,
@@ -61,6 +67,7 @@ class _HomesScreenState extends ConsumerState<HomesScreen> {
return Card(
margin: const EdgeInsets.only(bottom: 8),
child: ListTile(
enabled: !isBusy,
leading: Icon(
Icons.home,
color: isActive
@@ -87,25 +94,35 @@ class _HomesScreenState extends ConsumerState<HomesScreen> {
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(
Icons.edit,
size: 20,
color: Colors.white38,
if (isBusy)
const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
),
)
else ...[
IconButton(
icon: const Icon(
Icons.edit,
size: 20,
color: Colors.white38,
),
onPressed: () => _editHome(context, home),
),
onPressed: () => _editHome(context, home),
),
IconButton(
icon: const Icon(
Icons.delete_outline,
size: 20,
color: Colors.redAccent,
IconButton(
icon: const Icon(
Icons.delete_outline,
size: 20,
color: Colors.redAccent,
),
onPressed: () => _confirmDelete(context, home),
),
onPressed: () => _confirmDelete(context, home),
),
],
],
),
onTap: () => _selectHome(context, home),
onTap: isBusy ? null : () => _selectHome(context, home),
),
);
},
@@ -126,9 +143,12 @@ class _HomesScreenState extends ConsumerState<HomesScreen> {
}
void _selectHome(BuildContext context, HomeConfig home) async {
if (_switchingHomeId != null || _deletingHomeId != null) return;
setState(() => _switchingHomeId = home.id);
final messenger = ScaffoldMessenger.of(context);
try {
await ref.read(currentHomeProvider.notifier).switchTo(home);
await ref.read(authInfoProvider.notifier).load(failOnError: true);
await ref.read(currentHomeProvider.notifier).select(home);
if (context.mounted) {
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (_) => const RemoteScreen()),
@@ -136,9 +156,17 @@ class _HomesScreenState extends ConsumerState<HomesScreen> {
}
} catch (e) {
if (context.mounted) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Не удалось выбрать дом: $e')));
messenger.showSnackBar(
SnackBar(
content: Text(
'Не удалось выбрать дом: ${describeLoadError(e)}',
),
),
);
}
} finally {
if (mounted) {
setState(() => _switchingHomeId = null);
}
}
}
@@ -169,8 +197,7 @@ class _HomesScreenState extends ConsumerState<HomesScreen> {
TextButton(
onPressed: () async {
Navigator.of(ctx).pop();
await ref.read(homesProvider.notifier).remove(home.id);
await syncGeofenceTask(ref.read(homesProvider));
await _deleteHome(context, home);
},
child: const Text(
'Удалить',
@@ -181,6 +208,37 @@ class _HomesScreenState extends ConsumerState<HomesScreen> {
),
);
}
Future<void> _deleteHome(BuildContext context, HomeConfig home) async {
if (_switchingHomeId != null || _deletingHomeId != null) return;
final deletedCurrentHome = ref.read(currentHomeProvider)?.id == home.id;
setState(() => _deletingHomeId = home.id);
final messenger = ScaffoldMessenger.of(context);
try {
await ref.read(homesProvider.notifier).remove(home.id);
await ref.read(currentHomeProvider.notifier).load();
if (deletedCurrentHome) {
ref.read(authInfoProvider.notifier).clear();
}
await syncGeofenceTask(ref.read(homesProvider));
} catch (e) {
if (context.mounted) {
messenger.showSnackBar(
SnackBar(
content: Text(
'Не удалось удалить дом: ${describeLoadError(e)}',
),
),
);
}
} finally {
if (mounted) {
setState(() => _deletingHomeId = null);
}
}
}
}
class _EmptyHomesView extends StatelessWidget {

View File

@@ -39,8 +39,8 @@ class _RemoteScreenState extends ConsumerState<RemoteScreen> {
final groups = ref.watch(groupsProvider);
final groupsLoadState = ref.watch(groupsLoadStateProvider);
final currentHome = ref.watch(currentHomeProvider);
final authInfo = ref.watch(authInfoProvider);
final isAdmin = authInfo?.isAdmin == true;
final authInfoState = ref.watch(authInfoProvider);
final isAdmin = authInfoState.data?.isAdmin == true;
return Scaffold(
appBar: AppBar(