feat: implement real-time database synchronization with SSE and update backend modules
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'dart:async';
|
||||
|
||||
import '../../../core/api/api_error_mapper.dart';
|
||||
import '../../../core/l10n/l10n.dart';
|
||||
import '../../../core/realtime/realtime_sync.dart';
|
||||
import 'admin_ai_panel.dart';
|
||||
import 'admin_aliases_panel.dart';
|
||||
import 'admin_inventory_panel.dart';
|
||||
@@ -38,6 +40,32 @@ class AdminDatabasePanel extends ConsumerStatefulWidget {
|
||||
class _AdminDatabasePanelState extends ConsumerState<AdminDatabasePanel> {
|
||||
_DatabaseTab _activeTab = _DatabaseTab.inventory;
|
||||
bool _isRefreshingCategories = false;
|
||||
int _panelRefreshVersion = 0;
|
||||
ProviderSubscription<int>? _realtimeTickSubscription;
|
||||
Timer? _realtimeDebounce;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_realtimeTickSubscription = ref.listenManual<int>(
|
||||
realtimeRefreshTickProvider,
|
||||
(_, __) {
|
||||
if (!mounted) return;
|
||||
_realtimeDebounce?.cancel();
|
||||
_realtimeDebounce = Timer(const Duration(milliseconds: 600), () {
|
||||
if (!mounted) return;
|
||||
setState(() => _panelRefreshVersion++);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_realtimeDebounce?.cancel();
|
||||
_realtimeTickSubscription?.close();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
List<_DatabaseTabConfig> get _tabConfigs => [
|
||||
_DatabaseTabConfig(
|
||||
@@ -153,7 +181,12 @@ class _AdminDatabasePanelState extends ConsumerState<AdminDatabasePanel> {
|
||||
children: [
|
||||
header,
|
||||
const SizedBox(height: 12),
|
||||
Expanded(child: currentTab.panel),
|
||||
Expanded(
|
||||
child: KeyedSubtree(
|
||||
key: ValueKey('admin-db-${_activeTab.name}-$_panelRefreshVersion'),
|
||||
child: currentTab.panel,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'dart:async';
|
||||
|
||||
import '../../../core/api/api_error_mapper.dart';
|
||||
import '../../../core/l10n/l10n.dart';
|
||||
import '../../../core/realtime/realtime_sync.dart';
|
||||
import '../data/admin_repository.dart';
|
||||
import '../domain/user_admin.dart';
|
||||
|
||||
@@ -28,6 +30,8 @@ class _AdminUsersPanelState extends ConsumerState<AdminUsersPanel> {
|
||||
bool _filterPremiumOnly = false;
|
||||
bool _filterSharingOffOnly = false;
|
||||
List<UserAdmin> _users = [];
|
||||
ProviderSubscription<int>? _realtimeTickSubscription;
|
||||
Timer? _realtimeDebounce;
|
||||
|
||||
String _sortLabel(_UserSort sort) => switch (sort) {
|
||||
_UserSort.newest => 'Nyast',
|
||||
@@ -71,11 +75,24 @@ class _AdminUsersPanelState extends ConsumerState<AdminUsersPanel> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
_searchCtrl = TextEditingController();
|
||||
_realtimeTickSubscription = ref.listenManual<int>(
|
||||
realtimeRefreshTickProvider,
|
||||
(_, __) {
|
||||
if (!mounted) return;
|
||||
_realtimeDebounce?.cancel();
|
||||
_realtimeDebounce = Timer(const Duration(milliseconds: 600), () {
|
||||
if (!mounted) return;
|
||||
_load();
|
||||
});
|
||||
},
|
||||
);
|
||||
_load();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_realtimeDebounce?.cancel();
|
||||
_realtimeTickSubscription?.close();
|
||||
_searchCtrl.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user