fix: stabilize auth and home error flows
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user