feat: integrate invite API and improve notification handling
- Add invite code display and binding functionality via API - Fix notification unread count sync on auth state change - Improve notification mark read with server state validation - Add auth state listener to trigger notification refresh - Add YaoCoinConverter for coin-to-yao type conversion - Remove YaoLegend from divination screens (UI cleanup) - Abbreviate relation labels in yao detail view - Add re-register notice to account delete screen - Update 'coins' terminology to 'points' in localization - Fix backend points consumption to only run in CHAT mode - Add HttpxAuthNoiseFilter to suppress auth endpoint logging - Fix notification static_schema import path - Add test coverage for notification bloc error handling - Update AGENTS.md page header rules and image handling - Delete deprecated run-dev.sh script
This commit is contained in:
@@ -185,58 +185,64 @@ class NotificationBloc extends ChangeNotifier {
|
||||
}
|
||||
|
||||
Future<void> _markRead(String notificationId) async {
|
||||
final previousItems = _state.items;
|
||||
final previousCount = _state.unreadCount;
|
||||
final idx = _state.items.indexWhere((item) => item.id == notificationId);
|
||||
if (idx == -1) return;
|
||||
if (_state.items[idx].isRead) return;
|
||||
|
||||
final wasUnread = !_state.items[idx].isRead;
|
||||
_state = _state.copyWith(
|
||||
items: [
|
||||
..._state.items.sublist(0, idx),
|
||||
_state.items[idx].copyWith(isRead: true),
|
||||
..._state.items.sublist(idx + 1),
|
||||
],
|
||||
unreadCount: wasUnread
|
||||
? (_state.unreadCount > 0 ? _state.unreadCount - 1 : 0)
|
||||
: _state.unreadCount,
|
||||
_logger.info(
|
||||
message: 'Mark notification read started',
|
||||
extra: {'notification_id': notificationId},
|
||||
);
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
await _repository.markRead(notificationId: notificationId);
|
||||
final updated = await _repository.markRead(
|
||||
notificationId: notificationId,
|
||||
);
|
||||
final targetIndex = _state.items.indexWhere(
|
||||
(item) => item.id == updated.id,
|
||||
);
|
||||
if (targetIndex == -1) {
|
||||
return;
|
||||
}
|
||||
_state = _state.copyWith(
|
||||
items: [
|
||||
..._state.items.sublist(0, targetIndex),
|
||||
updated,
|
||||
..._state.items.sublist(targetIndex + 1),
|
||||
],
|
||||
unreadCount: _state.unreadCount > 0 ? _state.unreadCount - 1 : 0,
|
||||
);
|
||||
notifyListeners();
|
||||
_logger.info(
|
||||
message: 'Mark notification read succeeded',
|
||||
extra: {'notification_id': notificationId},
|
||||
);
|
||||
} catch (error, stackTrace) {
|
||||
_logger.error(
|
||||
message: 'Mark read failed: ${error.runtimeType}',
|
||||
error: error,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
_state = _state.copyWith(
|
||||
items: previousItems,
|
||||
unreadCount: previousCount,
|
||||
);
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _markAllRead() async {
|
||||
final previousItems = _state.items;
|
||||
_state = _state.copyWith(
|
||||
items: _state.items.map((item) => item.copyWith(isRead: true)).toList(),
|
||||
unreadCount: 0,
|
||||
);
|
||||
notifyListeners();
|
||||
_logger.info(message: 'Mark all notifications read started');
|
||||
|
||||
try {
|
||||
await _repository.markAllRead();
|
||||
_state = _state.copyWith(
|
||||
items: _state.items.map((item) => item.copyWith(isRead: true)).toList(),
|
||||
unreadCount: 0,
|
||||
);
|
||||
notifyListeners();
|
||||
_logger.info(message: 'Mark all notifications read succeeded');
|
||||
} catch (error, stackTrace) {
|
||||
_logger.error(
|
||||
message: 'Mark all read failed: ${error.runtimeType}',
|
||||
error: error,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
_state = _state.copyWith(items: previousItems);
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user