feat(apps/home): 新增 HomeScreen 录音交互与导航组件

This commit is contained in:
zl-q
2026-03-19 00:51:52 +08:00
parent 14ccf2cb28
commit 039e8b73d6
13 changed files with 1840 additions and 847 deletions
@@ -7,6 +7,7 @@ import 'package:image_picker/image_picker.dart';
import 'package:social_app/core/api/i_api_client.dart';
import 'package:social_app/core/di/injection.dart';
import 'package:social_app/features/chat/presentation/bloc/chat_bloc.dart';
import 'package:social_app/features/chat/data/models/chat_list_item.dart';
import 'package:social_app/features/home/data/voice_recorder.dart';
import 'package:social_app/features/home/ui/screens/home_screen.dart';
import 'package:social_app/features/home/ui/widgets/home_attachment_strip.dart';
@@ -127,6 +128,18 @@ void main() {
await tester.pump();
}
List<ChatListItem> buildMessages(int count) {
final base = DateTime(2026, 1, 1, 9, 0);
return List<ChatListItem>.generate(count, (index) {
return TextMessageItem(
id: 'msg_$index',
content: 'message $index',
timestamp: base.add(Duration(minutes: index)),
sender: index.isEven ? MessageSender.user : MessageSender.ai,
);
});
}
testWidgets(
'home screen shows floating header, conversation stage, and bottom input stack',
(tester) async {
@@ -292,4 +305,68 @@ void main() {
expect(recorder.stopCalls, 1);
expect(transcribeCalls, 0);
});
testWidgets(
'shows unread badge when new message arrives during history reading',
(tester) async {
await pumpHomeScreen(tester);
final initialItems = buildMessages(30);
chatBloc.emit(const ChatState().copyWith(items: initialItems));
await tester.pump(const Duration(milliseconds: 700));
final position = tester
.state<ScrollableState>(find.byType(Scrollable))
.position;
position.jumpTo(0);
await tester.pump(const Duration(milliseconds: 220));
final nextItems = [
...initialItems,
...buildMessages(1).map(
(e) => (e as TextMessageItem).copyWith(
id: 'new_1',
content: 'new message',
),
),
];
chatBloc.emit(const ChatState().copyWith(items: nextItems));
await tester.pump(const Duration(milliseconds: 700));
expect(find.textContaining('有1条新消息'), findsOneWidget);
},
);
testWidgets('tap unread badge scrolls bottom and clears badge', (
tester,
) async {
await pumpHomeScreen(tester);
final initialItems = buildMessages(30);
chatBloc.emit(const ChatState().copyWith(items: initialItems));
await tester.pump(const Duration(milliseconds: 700));
final position = tester
.state<ScrollableState>(find.byType(Scrollable))
.position;
position.jumpTo(0);
await tester.pump(const Duration(milliseconds: 220));
final nextItems = [
...initialItems,
...buildMessages(1).map(
(e) => (e as TextMessageItem).copyWith(
id: 'new_2',
content: 'new message 2',
),
),
];
chatBloc.emit(const ChatState().copyWith(items: nextItems));
await tester.pump(const Duration(milliseconds: 700));
await tester.tap(find.textContaining('有1条新消息'));
await tester.pump(const Duration(milliseconds: 700));
expect(find.textContaining('有1条新消息'), findsNothing);
});
}