diff --git a/lib/view/channels_page/channel_detail_page.dart b/lib/view/channels_page/channel_detail_page.dart index b5b660a56..7085958c7 100644 --- a/lib/view/channels_page/channel_detail_page.dart +++ b/lib/view/channels_page/channel_detail_page.dart @@ -5,6 +5,7 @@ import "package:hooks_riverpod/hooks_riverpod.dart"; import "package:miria/providers.dart"; import "package:miria/router/app_router.dart"; import "package:miria/view/channels_page/channel_detail_info.dart"; +import "package:miria/view/channels_page/channel_note_highlight.dart"; import "package:miria/view/channels_page/channel_timeline.dart"; import "package:miria/view/common/account_scope.dart"; @@ -26,7 +27,7 @@ class ChannelDetailPage extends ConsumerWidget implements AutoRouteWrapper { @override Widget build(BuildContext context, WidgetRef ref) { return DefaultTabController( - length: 2, + length: 3, child: Scaffold( appBar: AppBar( title: Text(S.of(context).channel), @@ -34,6 +35,7 @@ class ChannelDetailPage extends ConsumerWidget implements AutoRouteWrapper { tabs: [ Tab(child: Text(S.of(context).channelInformation)), Tab(child: Text(S.of(context).timeline)), + Tab(child: Text(S.of(context).highlight)), ], ), ), @@ -49,6 +51,10 @@ class ChannelDetailPage extends ConsumerWidget implements AutoRouteWrapper { padding: const EdgeInsets.only(left: 10, right: 10), child: ChannelTimeline(channelId: channelId), ), + Padding( + padding: const EdgeInsets.only(left: 10, right: 10), + child: ChannelNoteHighlight(channelId: channelId), + ), ], ), floatingActionButton: ref.read(accountContextProvider).isSame diff --git a/lib/view/channels_page/channel_note_highlight.dart b/lib/view/channels_page/channel_note_highlight.dart new file mode 100644 index 000000000..2050e855f --- /dev/null +++ b/lib/view/channels_page/channel_note_highlight.dart @@ -0,0 +1,43 @@ +import "package:flutter/material.dart"; +import "package:hooks_riverpod/hooks_riverpod.dart"; +import "package:miria/providers.dart"; +import "package:miria/view/common/misskey_notes/misskey_note.dart"; +import "package:miria/view/common/pushable_listview.dart"; +import "package:misskey_dart/misskey_dart.dart"; + +class ChannelNoteHighlight extends ConsumerWidget { + final String channelId; + const ChannelNoteHighlight({ + required this.channelId, + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return PushableListView( + initializeFuture: () async { + final response = await ref + .read(misskeyGetContextProvider) + .notes + .featured(NotesFeaturedRequest(channelId: channelId)); + + ref.read(notesWithProvider).registerAll(response); + return response.toList(); + }, + nextFuture: (item, index) async { + final response = + await ref.read(misskeyGetContextProvider).notes.featured( + NotesFeaturedRequest( + offset: index, + untilId: item.id, + channelId: channelId, + ), + ); + + ref.read(notesWithProvider).registerAll(response); + return response.toList(); + }, + itemBuilder: (context, item) => MisskeyNote(note: item), + ); + } +} diff --git a/test/view/channel_detail_page/channel_detail_page_test.dart b/test/view/channel_detail_page/channel_detail_page_test.dart index a4632fe45..c1f3e2b57 100644 --- a/test/view/channel_detail_page/channel_detail_page_test.dart +++ b/test/view/channel_detail_page/channel_detail_page_test.dart @@ -259,5 +259,59 @@ void main() { ), ); }); + + testWidgets("チャンネル内のハイライトノートが表示されること", (tester) async { + final notes = MockMisskeyNotes(); + final channel = MockMisskeyChannels(); + final misskey = MockMisskey(); + when(misskey.channels).thenReturn(channel); + when(channel.show(any)).thenAnswer( + (_) async => + TestData.channel1.copyWith(bannerUrl: null, isFollowing: false), + ); + + when(misskey.notes).thenReturn(notes); + when(notes.featured(any)).thenAnswer((_) async => [TestData.note1]); + + await tester.pumpWidget( + ProviderScope( + overrides: [misskeyProvider.overrideWith((_) => misskey)], + child: DefaultRootWidget( + initialRoute: ChannelDetailRoute( + accountContext: TestData.accountContext, + channelId: TestData.channel1.id, + ), + ), + ), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.text("ハイライト")); + await tester.pumpAndSettle(); + + expect(find.text(TestData.note1.text!), findsOneWidget); + + verify( + notes.featured( + argThat( + equals(NotesFeaturedRequest(channelId: TestData.channel1.id)), + ), + ), + ); + await tester.pageNation(); + verify( + notes.featured( + argThat( + equals( + NotesFeaturedRequest( + untilId: TestData.note1.id, + offset: 1, + channelId: TestData.channel1.id, + ), + ), + ), + ), + ); + }); }); }