feat(apps/home): 新增 HomeScreen 录音交互与导航组件
This commit is contained in:
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user