diff --git a/lib/pages/new_private_chat/widget/no_contacts_found.dart b/lib/pages/new_private_chat/widget/no_contacts_found.dart index b5baabdb6e..b5d6b495ee 100644 --- a/lib/pages/new_private_chat/widget/no_contacts_found.dart +++ b/lib/pages/new_private_chat/widget/no_contacts_found.dart @@ -10,59 +10,9 @@ class NoContactsFound extends StatelessWidget { @override Widget build(BuildContext context) { return keyword != null - ? Padding( - padding: const EdgeInsets.only(left: 8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - L10n.of(context)!.noResultForKeyword(keyword!), - style: Theme.of(context).textTheme.titleLarge, - ), - const SizedBox( - height: 8.0, - ), - Text.rich( - TextSpan( - style: Theme.of(context).textTheme.bodyMedium, - children: [ - TextSpan( - children: [ - TextSpan( - text: L10n.of(context)!.searchResultNotFound1, - ), - TextSpan( - text: L10n.of(context)!.searchResultNotFound2, - ), - TextSpan( - text: L10n.of(context)!.searchResultNotFound3, - ), - TextSpan( - text: L10n.of(context)!.searchResultNotFound4, - ), - TextSpan( - text: L10n.of(context)!.searchResultNotFound5, - style: Theme.of(context) - .textTheme - .bodyMedium - ?.copyWith( - color: Theme.of(context).colorScheme.primary, - ), - ), - ], - ), - ], - ), - ), - const SizedBox( - height: 8.0, - ), - const Align( - alignment: Alignment.center, - child: EmptySearchWidget(), - ), - ], - ), + ? const Align( + alignment: Alignment.center, + child: EmptySearchWidget(), ) : SizedBox( height: MediaQuery.sizeOf(context).height * 0.7, diff --git a/lib/pages/search/search.dart b/lib/pages/search/search.dart index 458e201aa5..9ae0ea5d7a 100644 --- a/lib/pages/search/search.dart +++ b/lib/pages/search/search.dart @@ -58,6 +58,9 @@ class SearchController extends State { String get searchWord => textEditingController.text; + bool get isSearchMatrixUserId => + searchWord.isValidMatrixId && searchWord.startsWith('@'); + String getBodyText(Event event, String searchWord) { final senderName = event.senderFromMemoryOrFallback.calcDisplayname( i18n: MatrixLocals(L10n.of(context)!), diff --git a/lib/pages/search/search_view.dart b/lib/pages/search/search_view.dart index ac42c1cf2e..540653481f 100644 --- a/lib/pages/search/search_view.dart +++ b/lib/pages/search/search_view.dart @@ -13,7 +13,6 @@ import 'package:fluffychat/widgets/twake_components/twake_loading/center_loading import 'package:flutter/material.dart' hide SearchController; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:linagora_design_flutter/colors/linagora_sys_colors.dart'; -import 'package:matrix/matrix.dart'; class SearchView extends StatelessWidget { final SearchController searchController; @@ -73,15 +72,7 @@ class SearchView extends StatelessWidget { searchController.serverSearchController.searchResultsNotifier, builder: ((context, searchResults, child) { if (searchResults is PresentationServerSideEmptySearch) { - if (searchController.searchContactAndRecentChatController! - .recentAndContactsNotifier.value.isNotEmpty) { - return child!; - } - return _SearchHeader( - header: L10n.of(context)!.messages, - searchController: searchController, - needShowMore: false, - ); + return child!; } if (searchResults is PresentationServerSideSearch) { @@ -128,7 +119,7 @@ class SearchView extends StatelessWidget { builder: (context, contacts, emptyChild) { if (contacts.isEmpty) { final keyword = searchController.textEditingController.text; - if (keyword.isValidMatrixId && keyword.startsWith("@")) { + if (searchController.isSearchMatrixUserId) { return SearchExternalContactWidget( keyword: keyword, searchController: searchController, diff --git a/lib/pages/search/server_search_view.dart b/lib/pages/search/server_search_view.dart index 07a1512202..1e3f8b818e 100644 --- a/lib/pages/search/server_search_view.dart +++ b/lib/pages/search/server_search_view.dart @@ -29,10 +29,11 @@ class ServerSearchMessagesList extends StatelessWidget { builder: (context, serverSearchNotifier, child) { if (serverSearchNotifier is PresentationServerSideEmptySearch) { if (searchController.searchContactAndRecentChatController! - .recentAndContactsNotifier.value.isNotEmpty) { - return const SizedBox.shrink(); + .recentAndContactsNotifier.value.isEmpty && + !(searchController.isSearchMatrixUserId)) { + return child!; } - return child!; + return const SizedBox.shrink(); } if (serverSearchNotifier is PresentationServerSideSearch) { diff --git a/test/pages/search/server_search_view_test.dart b/test/pages/search/server_search_view_test.dart new file mode 100644 index 0000000000..be65665af3 --- /dev/null +++ b/test/pages/search/server_search_view_test.dart @@ -0,0 +1,154 @@ +import 'package:fluffychat/config/localizations/localization_service.dart'; +import 'package:fluffychat/config/themes.dart'; +import 'package:fluffychat/pages/search/search.dart'; +import 'package:fluffychat/pages/search/search_contacts_and_chats_controller.dart'; +import 'package:fluffychat/pages/search/server_search_controller.dart'; +import 'package:fluffychat/pages/search/server_search_view.dart'; +import 'package:fluffychat/presentation/model/search/presentation_search.dart'; +import 'package:fluffychat/presentation/model/search/presentation_server_side_empty_search.dart'; +import 'package:fluffychat/presentation/model/search/presentation_server_side_state.dart'; +import 'package:fluffychat/utils/custom_scroll_behaviour.dart'; +import 'package:fluffychat/utils/responsive/responsive_utils.dart'; +import 'package:fluffychat/widgets/search/empty_search_widget.dart'; +import 'package:fluffychat/widgets/theme_builder.dart'; +import 'package:flutter/material.dart' hide SearchController; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:flutter_localized_locales/flutter_localized_locales.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:get_it/get_it.dart'; +import 'package:linagora_design_flutter/linagora_design_flutter.dart'; +import 'package:mockito/annotations.dart'; +import 'package:flutter_gen/gen_l10n/l10n.dart'; +import 'package:mockito/mockito.dart'; +import 'server_search_view_test.mocks.dart'; + +@GenerateNiceMocks([ + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), +]) +void main() { + late final SearchController mockSearchController; + late final ServerSearchController mockServerSearchController; + late final TextEditingController mockTextEditingController; + late final SearchContactsAndChatsController + mockSearchContactAndRecentChatController; + + setUpAll(() { + final getIt = GetIt.instance; + getIt.registerSingleton(ResponsiveUtils()); + mockSearchController = MockSearchController(); + mockServerSearchController = MockServerSearchController(); + mockTextEditingController = MockTextEditingController(); + mockSearchContactAndRecentChatController = + MockSearchContactsAndChatsController(); + }); + + Future makeTestable(WidgetTester tester) async { + await tester.pumpWidget( + ThemeBuilder( + builder: (context, themeMode, primaryColor) => MaterialApp( + locale: const Locale('en'), + scrollBehavior: CustomScrollBehavior(), + localizationsDelegates: const [ + LocaleNamesLocalizationsDelegate(), + L10n.delegate, + GlobalMaterialLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ], + supportedLocales: LocalizationService.supportedLocales, + theme: TwakeThemes.buildTheme( + context, + Brightness.light, + primaryColor, + ), + home: Scaffold( + backgroundColor: LinagoraSysColors.material().onPrimary, + body: CustomScrollView( + physics: const ClampingScrollPhysics(), + slivers: [ + ServerSearchMessagesList( + searchController: mockSearchController, + ), + ], + ), + ), + ), + ), + ); + } + + group('[ServerSearchMessagesList] TEST', () { + group('GIVEN searchResultsNotifier is PresentationServerSideEmptySearch', + () { + testWidgets( + 'GIVEN notifier value is empty\n' + 'AND recentAndContactsNotifier value is empty\n' + 'AND keyword is a Matrix ID\n' + 'THEN should display SizedBox.shrink\n', + (WidgetTester tester) async { + when(mockSearchController.serverSearchController) + .thenReturn(mockServerSearchController); + when(mockSearchController.textEditingController) + .thenReturn(mockTextEditingController); + when(mockSearchController.searchContactAndRecentChatController) + .thenReturn( + mockSearchContactAndRecentChatController, + ); + when(mockTextEditingController.text).thenReturn('@test:domain.com'); + when(mockServerSearchController.searchResultsNotifier).thenReturn( + ValueNotifier( + PresentationServerSideEmptySearch(), + ), + ); + when( + mockSearchContactAndRecentChatController.recentAndContactsNotifier, + ).thenReturn(ValueNotifier>([])); + + await makeTestable(tester); + + expect(find.byType(SizedBox), findsOneWidget); + + final SizedBox foundSizedBox = + tester.firstWidget(find.byType(SizedBox)); + expect(foundSizedBox.child, isNull); + expect(foundSizedBox.width, equals(0)); + expect(foundSizedBox.height, equals(0)); + }, + ); + + testWidgets( + 'GIVEN searchResultsNotifier value is empty\n' + 'AND recentAndContactsNotifier value is empty\n' + 'AND keyword is not a Matrix ID\n' + 'THEN should display EmptySearchWidget\n', + (WidgetTester tester) async { + when(mockSearchController.serverSearchController) + .thenReturn(mockServerSearchController); + when(mockSearchController.textEditingController) + .thenReturn(mockTextEditingController); + when(mockSearchController.searchContactAndRecentChatController) + .thenReturn( + mockSearchContactAndRecentChatController, + ); + when(mockTextEditingController.text).thenReturn('test'); + when(mockServerSearchController.searchResultsNotifier).thenReturn( + ValueNotifier( + PresentationServerSideEmptySearch(), + ), + ); + when( + mockSearchContactAndRecentChatController.recentAndContactsNotifier, + ).thenReturn(ValueNotifier>([])); + + await makeTestable(tester); + await tester.pumpAndSettle(); + + expect(find.byType(EmptySearchWidget), findsOneWidget); + }, + ); + }); + }); +}