refactor(apps): 重构数据层目录结构并新增启动预热编排器

This commit is contained in:
zl-q
2026-03-29 20:26:30 +08:00
parent 33340de8f9
commit 4db9a13bfe
108 changed files with 1653 additions and 1320 deletions
@@ -1,4 +1,4 @@
import 'package:social_app/core/network/i_api_client.dart';
import 'package:social_app/data/network/i_api_client.dart';
class InboxApi {
final IApiClient _client;
@@ -0,0 +1,74 @@
enum InboxMessageType { friendRequest, calendar, system, group }
enum InboxMessageStatus { pending, accepted, rejected, dismissed }
class InboxMessage {
final String id;
final String recipientId;
final String? senderId;
final InboxMessageType messageType;
final String? scheduleItemId;
final String? friendshipId;
final Map<String, dynamic>? content;
final bool isRead;
final InboxMessageStatus status;
final DateTime createdAt;
const InboxMessage({
required this.id,
required this.recipientId,
required this.senderId,
required this.messageType,
required this.scheduleItemId,
required this.friendshipId,
required this.content,
required this.isRead,
required this.status,
required this.createdAt,
});
factory InboxMessage.fromJson(Map<String, dynamic> json) {
return InboxMessage(
id: json['id'] as String,
recipientId: json['recipient_id'] as String,
senderId: json['sender_id'] as String?,
messageType: _messageTypeFromApi(json['message_type'] as String),
scheduleItemId: json['schedule_item_id'] as String?,
friendshipId: json['friendship_id'] as String?,
content: json['content'] as Map<String, dynamic>?,
isRead: json['is_read'] as bool,
status: _messageStatusFromApi(json['status'] as String),
createdAt: DateTime.parse(json['created_at'] as String),
);
}
}
InboxMessageType _messageTypeFromApi(String raw) {
switch (raw) {
case 'friend_request':
return InboxMessageType.friendRequest;
case 'calendar':
return InboxMessageType.calendar;
case 'system':
return InboxMessageType.system;
case 'group':
return InboxMessageType.group;
default:
throw StateError('Unsupported inbox message type: $raw');
}
}
InboxMessageStatus _messageStatusFromApi(String raw) {
switch (raw) {
case 'pending':
return InboxMessageStatus.pending;
case 'accepted':
return InboxMessageStatus.accepted;
case 'rejected':
return InboxMessageStatus.rejected;
case 'dismissed':
return InboxMessageStatus.dismissed;
default:
throw StateError('Unsupported inbox message status: $raw');
}
}
@@ -0,0 +1,130 @@
import '../../../../data/network/i_api_client.dart';
import '../../../../data/cache/cache_policy.dart';
import '../../../../data/cache/cached_repository.dart';
import '../models/inbox_message.dart';
abstract class InboxRepository {
Future<List<InboxMessage>> getMessages({bool? isRead});
Future<InboxMessage> markAsRead(String messageId);
}
class InboxRepositoryImpl extends CachedRepository<List<InboxMessage>>
implements InboxRepository {
final IApiClient _apiClient;
static const _prefix = '/api/v1/inbox/messages';
InboxRepositoryImpl({required IApiClient apiClient, required super.store})
: _apiClient = apiClient,
super(
policy: const CachePolicy(
softTtl: Duration(seconds: 15),
hardTtl: Duration(minutes: 2),
minRefreshInterval: Duration(seconds: 10),
),
encodeValue: _encodeMessages,
decodeValue: _decodeMessages,
);
@override
Future<List<InboxMessage>> getMessages({bool? isRead}) async {
return getOrLoad(
key: _messagesKey(isRead),
loadFromRemote: () => _loadMessagesFromRemote(isRead: isRead),
);
}
Future<List<InboxMessage>> _loadMessagesFromRemote({bool? isRead}) async {
final queryParams = isRead != null ? '?is_read=$isRead' : '';
final response = await _apiClient.get<List<dynamic>>(
'$_prefix$queryParams',
);
final data = response.data;
if (data == null) {
throw StateError('Invalid getMessages response: empty payload');
}
return data
.whereType<Map<String, dynamic>>()
.map(InboxMessage.fromJson)
.toList(growable: false);
}
@override
Future<InboxMessage> markAsRead(String messageId) async {
final response = await _apiClient.patch<Map<String, dynamic>>(
'$_prefix/$messageId/read',
);
final data = response.data;
if (data == null) {
throw StateError('Invalid markAsRead response: empty payload');
}
final message = InboxMessage.fromJson(data);
await Future.wait([
removeCacheKey(_messagesKey(false)),
removeCacheKey(_messagesKey(true)),
removeCacheKey(_messagesKey(null)),
]);
return message;
}
static String _messagesKey(bool? isRead) {
if (isRead == null) {
return 'inbox:list:all';
}
return isRead ? 'inbox:list:read' : 'inbox:list:unread';
}
static Object? _encodeMessages(List<InboxMessage> messages) {
return messages.map(_encodeMessage).toList(growable: false);
}
static List<InboxMessage> _decodeMessages(Object? raw) {
if (raw is! List) {
throw const FormatException('Invalid cached inbox message payload');
}
return raw
.whereType<Map>()
.map((item) => InboxMessage.fromJson(Map<String, dynamic>.from(item)))
.toList(growable: false);
}
static Map<String, Object?> _encodeMessage(InboxMessage message) {
return <String, Object?>{
'id': message.id,
'recipient_id': message.recipientId,
'sender_id': message.senderId,
'message_type': _messageTypeToApi(message.messageType),
'schedule_item_id': message.scheduleItemId,
'friendship_id': message.friendshipId,
'content': message.content,
'is_read': message.isRead,
'status': _messageStatusToApi(message.status),
'created_at': message.createdAt.toIso8601String(),
};
}
static String _messageTypeToApi(InboxMessageType type) {
switch (type) {
case InboxMessageType.friendRequest:
return 'friend_request';
case InboxMessageType.calendar:
return 'calendar';
case InboxMessageType.system:
return 'system';
case InboxMessageType.group:
return 'group';
}
}
static String _messageStatusToApi(InboxMessageStatus status) {
switch (status) {
case InboxMessageStatus.pending:
return 'pending';
case InboxMessageStatus.accepted:
return 'accepted';
case InboxMessageStatus.rejected:
return 'rejected';
case InboxMessageStatus.dismissed:
return 'dismissed';
}
}
}
@@ -3,10 +3,10 @@ import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import '../../../../app/di/injection.dart';
import '../../../../data/repositories/calendar_event_repository.dart';
import '../../../../data/repositories/models/inbox_message.dart';
import '../../../../data/repositories/inbox_repository.dart';
import '../../../../data/repositories/user_repository.dart';
import '../../../../features/calendar/data/repositories/calendar_repository.dart';
import '../../../../features/messages/data/models/inbox_message.dart';
import '../../../../features/messages/data/repositories/inbox_repository.dart';
import '../../../../features/contacts/data/repositories/user_repository.dart';
import '../../../../core/l10n/l10n.dart';
import '../../../../shared/widgets/app_loading_indicator.dart';
import '../../../../shared/widgets/page_header.dart';
@@ -25,7 +25,7 @@ class MessageInviteDetailScreen extends StatefulWidget {
class _MessageInviteDetailScreenState extends State<MessageInviteDetailScreen> {
late final InboxRepository _inboxRepository;
late final CalendarEventRepository _calendarRepository;
late final CalendarRepository _calendarRepository;
late final UserRepository _userRepository;
InboxMessage? _message;
@@ -43,7 +43,7 @@ class _MessageInviteDetailScreenState extends State<MessageInviteDetailScreen> {
void initState() {
super.initState();
_inboxRepository = sl<InboxRepository>();
_calendarRepository = sl<CalendarEventRepository>();
_calendarRepository = sl<CalendarRepository>();
_userRepository = sl<UserRepository>();
_loadDetail();
}
@@ -3,10 +3,10 @@ import 'package:go_router/go_router.dart';
import '../../../../app/di/injection.dart';
import '../../../../app/router/app_routes.dart';
import '../../../../data/repositories/friend_repository.dart';
import '../../../../data/repositories/inbox_repository.dart';
import '../../../../data/repositories/models/friend_request.dart';
import '../../../../data/repositories/models/inbox_message.dart';
import '../../../../features/contacts/data/repositories/friend_repository.dart';
import '../../../../features/messages/data/repositories/inbox_repository.dart';
import '../../../../features/contacts/data/models/friend_request.dart';
import '../../../../features/messages/data/models/inbox_message.dart';
import '../../../../core/l10n/l10n.dart';
import '../../../../shared/widgets/app_loading_indicator.dart';
import '../../../../shared/widgets/app_pull_refresh_feedback.dart';
@@ -3,7 +3,7 @@ import 'package:social_app/core/l10n/l10n.dart';
import '../../../../core/theme/design_tokens.dart';
import '../../../../shared/widgets/app_button.dart';
import '../../data/inbox_api.dart';
import '../../data/apis/inbox_api.dart';
class CalendarInviteCard extends StatelessWidget {
final InboxMessageResponse message;