diff --git a/lib/pages/contacts_tab/contacts_tab_body_view.dart b/lib/pages/contacts_tab/contacts_tab_body_view.dart index 3502c066f1..f4302b3e84 100644 --- a/lib/pages/contacts_tab/contacts_tab_body_view.dart +++ b/lib/pages/contacts_tab/contacts_tab_body_view.dart @@ -1,23 +1,16 @@ -import 'package:fluffychat/domain/app_state/contact/get_contacts_state.dart'; import 'package:fluffychat/pages/contacts_tab/contacts_tab.dart'; import 'package:fluffychat/pages/contacts_tab/contacts_tab_view_style.dart'; -import 'package:fluffychat/pages/contacts_tab/empty_contacts_body.dart'; +import 'package:fluffychat/pages/contacts_tab/widgets/sliver_contacts_with_matrix_id.dart'; +import 'package:fluffychat/pages/contacts_tab/widgets/sliver_contacts_without_matrix_id.dart'; +import 'package:fluffychat/pages/contacts_tab/widgets/sliver_empty_contacts.dart'; import 'package:fluffychat/pages/contacts_tab/widgets/sliver_invite_friend_button.dart'; -import 'package:fluffychat/pages/new_private_chat/widget/expansion_contact_list_tile.dart'; -import 'package:fluffychat/pages/new_private_chat/widget/expansion_phonebook_contact_list_tile.dart'; -import 'package:fluffychat/pages/new_private_chat/widget/loading_contact_widget.dart'; -import 'package:fluffychat/pages/new_private_chat/widget/no_contacts_found.dart'; -import 'package:fluffychat/pages/search/recent_item_widget.dart'; -import 'package:fluffychat/presentation/model/contact/get_presentation_contacts_empty.dart'; -import 'package:fluffychat/presentation/model/contact/get_presentation_contacts_failure.dart'; -import 'package:fluffychat/presentation/model/contact/presentation_contact.dart'; -import 'package:fluffychat/presentation/model/contact/presentation_contact_success.dart'; -import 'package:fluffychat/presentation/model/search/presentation_search.dart'; +import 'package:fluffychat/pages/contacts_tab/widgets/sliver_loading_contacts.dart'; +import 'package:fluffychat/pages/contacts_tab/widgets/sliver_phonebook_contacts_with_matrix_id.dart'; +import 'package:fluffychat/pages/contacts_tab/widgets/sliver_phonebook_contacts_without_matrix_id.dart'; +import 'package:fluffychat/pages/contacts_tab/widgets/sliver_recent_contacts.dart'; +import 'package:fluffychat/pages/contacts_tab/widgets/sliver_warning_banner.dart'; import 'package:fluffychat/utils/platform_infos.dart'; -import 'package:fluffychat/widgets/contacts_warning_banner/contacts_warning_banner_view.dart'; -import 'package:fluffychat/widgets/sliver_expandable_list.dart'; import 'package:flutter/material.dart'; -import 'package:fluffychat/generated/l10n/app_localizations.dart'; class ContactsTabBodyView extends StatelessWidget { final ContactsTabController controller; @@ -30,392 +23,20 @@ class ContactsTabBodyView extends StatelessWidget { slivers: [ if (controller.client.userID != null) SliverInviteFriendButton(userId: controller.client.userID!), - _SliverWarningBanner(controller: controller), - _SliverRecentContacts(controller: controller), - _SliverContactsList(controller: controller), + SliverWarningBanner(controller: controller), + SliverRecentContacts(controller: controller), + SliverLoadingContacts(controller: controller), + SliverContactsWithMatrixId(controller: controller), if (PlatformInfos.isMobile) - _SliverPhonebookList(controller: controller), - const _SliverPadding(), - ], - ); - } -} - -class _SliverPadding extends StatelessWidget { - const _SliverPadding(); - - @override - Widget build(BuildContext context) { - return const SliverToBoxAdapter( - child: SizedBox(height: ContactsTabViewStyle.padding), - ); - } -} - -class _SliverPhonebookList extends StatelessWidget { - const _SliverPhonebookList({required this.controller}); - - final ContactsTabController controller; - - @override - Widget build(BuildContext context) { - return ValueListenableBuilder( - valueListenable: controller.presentationPhonebookContactNotifier, - builder: (context, phonebookContactState, child) { - return phonebookContactState.fold( - (failure) { - if (!PlatformInfos.isMobile) { - return child!; - } - final presentationRecentContact = - controller.presentationRecentContactNotifier.value; - if (failure is GetPresentationContactsFailure) { - if (presentationRecentContact.isEmpty) { - return controller.presentationContactNotifier.value.fold(( - failure, - ) { - if (failure is GetPresentationContactsFailure || - failure is GetPresentationContactsEmpty) { - return SliverToBoxAdapter( - child: Padding( - padding: const EdgeInsets.only( - left: ContactsTabViewStyle.padding, - top: ContactsTabViewStyle.padding, - ), - child: NoContactsFound( - keyword: controller.textEditingController.text.isEmpty - ? null - : controller.textEditingController.text, - ), - ), - ); - } - return child!; - }, (_) => child!); - } - } - if (failure is GetPresentationContactsEmpty) { - if (presentationRecentContact.isEmpty) { - return controller.presentationContactNotifier.value.fold(( - failure, - ) { - if (failure is GetPresentationContactsFailure || - failure is GetPresentationContactsEmpty) { - if (controller.textEditingController.text.isEmpty) { - return const SliverToBoxAdapter( - child: EmptyContactBody(), - ); - } else { - return SliverToBoxAdapter( - child: Padding( - padding: const EdgeInsets.only( - left: ContactsTabViewStyle.padding, - top: ContactsTabViewStyle.padding, - ), - child: NoContactsFound( - keyword: controller.textEditingController.text, - ), - ), - ); - } - } - return child!; - }, (_) => child!); - } - } - return child!; - }, - (success) { - if (success is PresentationContactsSuccess) { - final contacts = success.contacts; - - return SliverExpandableList( - title: L10n.of(context)!.contactsCount(contacts.length), - itemCount: contacts.length, - itemBuilder: (context, index) => _PhonebookContact( - contact: contacts[index], - controller: controller, - ), - ); - } - return child!; - }, - ); - }, - child: const SliverToBoxAdapter(child: SizedBox()), - ); - } -} - -class _SliverContactsList extends StatelessWidget { - const _SliverContactsList({required this.controller}); - - final ContactsTabController controller; - - @override - Widget build(BuildContext context) { - return ValueListenableBuilder( - valueListenable: controller.presentationContactNotifier, - builder: (context, state, child) { - return state.fold( - (failure) { - if (PlatformInfos.isMobile) { - return child!; - } - final presentationRecentContact = - controller.presentationRecentContactNotifier.value; - - if (presentationRecentContact.isNotEmpty) { - return child!; - } - if (PlatformInfos.isWeb) { - if (failure is GetPresentationContactsFailure || - failure is GetPresentationContactsEmpty) { - final keyword = controller.textEditingController.text; - if (keyword.isEmpty) { - return const SliverToBoxAdapter(child: EmptyContactBody()); - } else { - return SliverToBoxAdapter( - child: Padding( - padding: const EdgeInsets.only( - left: ContactsTabViewStyle.padding, - top: ContactsTabViewStyle.padding, - ), - child: NoContactsFound( - keyword: controller.textEditingController.text, - ), - ), - ); - } - } - return child!; - } else { - return controller.presentationPhonebookContactNotifier.value.fold( - (_) { - if (controller.presentationPhonebookContactNotifier.value - .isRight()) { - return child!; - } - if (failure is GetPresentationContactsFailure || - failure is GetPresentationContactsEmpty) { - final keyword = controller.textEditingController.text; - if (keyword.isEmpty) { - return const SliverToBoxAdapter( - child: EmptyContactBody(), - ); - } else { - return SliverToBoxAdapter( - child: Padding( - padding: const EdgeInsets.only( - left: ContactsTabViewStyle.padding, - top: ContactsTabViewStyle.padding, - ), - child: NoContactsFound( - keyword: controller.textEditingController.text, - ), - ), - ); - } - } - return child!; - }, - (success) => child!, - ); - } - }, - (success) { - if (success is ContactsLoading) { - return const SliverToBoxAdapter(child: LoadingContactWidget()); - } - - if (success is PresentationExternalContactSuccess) { - if (controller - .presentationRecentContactNotifier - .value - .isNotEmpty) { - return child!; - } - - if (!PlatformInfos.isWeb) { - if (controller.phoneBookFilterSuccess) { - return child!; - } - } - - final externalContact = success.contact; - return _SilverExternalContact( - controller: controller, - externalContact: externalContact, - ); - } - - if (success is PresentationContactsSuccess) { - final contacts = success.contacts; - return SliverExpandableList( - title: L10n.of(context)!.linagoraContactsCount(contacts.length), - itemCount: contacts.length, - itemBuilder: (context, index) => - _Contact(contact: contacts[index], controller: controller), - ); - } - - return child!; - }, - ); - }, - child: const SliverToBoxAdapter(child: SizedBox()), - ); - } -} - -class _SilverExternalContact extends StatelessWidget { - final ContactsTabController controller; - final PresentationContact externalContact; - - const _SilverExternalContact({ - required this.controller, - required this.externalContact, - }); - - @override - Widget build(BuildContext context) { - return SliverToBoxAdapter( - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: ContactsTabViewStyle.padding, - ), - child: ExpansionContactListTile( - contact: externalContact, - highlightKeyword: controller.textEditingController.text, - enableInvitation: controller.supportInvitation(), - onContactTap: () => controller.onContactTap( - context: context, - path: 'rooms', - contact: externalContact, - ), - ), - ), - ); - } -} - -class _SliverRecentContacts extends StatelessWidget { - final ContactsTabController controller; - - const _SliverRecentContacts({required this.controller}); - - @override - Widget build(BuildContext context) { - return ValueListenableBuilder( - valueListenable: controller.presentationContactNotifier, - builder: (context, state, child) { - return state.fold((failure) => child!, (success) { - if (success is ContactsLoading) { - return const SliverToBoxAdapter(child: SizedBox()); - } - return child!; - }); - }, - child: ValueListenableBuilder( - valueListenable: controller.presentationRecentContactNotifier, - builder: (context, recentContacts, child) { - if (recentContacts.isEmpty) { - return child!; - } - return SliverExpandableList( - title: L10n.of(context)!.recent, - itemCount: recentContacts.length, - itemBuilder: (context, index) => Padding( - padding: const EdgeInsets.symmetric( - horizontal: ContactsTabViewStyle.padding, - ), - child: RecentItemWidget( - presentationSearch: recentContacts[index], - highlightKeyword: controller.textEditingController.text, - client: controller.client, - key: Key('contact_recent_${recentContacts[index].id}'), - onTap: () => controller.onContactTap( - contact: recentContacts[index].toPresentationContact(), - context: context, - path: 'rooms', - ), - avatarSize: ContactsTabViewStyle.avatarSize, - ), - ), - ); - }, - child: const SliverToBoxAdapter(child: SizedBox()), - ), - ); - } -} - -class _SliverWarningBanner extends StatelessWidget { - const _SliverWarningBanner({required this.controller}); - - final ContactsTabController controller; - - @override - Widget build(BuildContext context) { - return SliverToBoxAdapter( - child: ContactsWarningBannerView( - warningBannerNotifier: controller.warningBannerNotifier, - closeContactsWarningBanner: controller.closeContactsWarningBanner, - goToSettingsForPermissionActions: () => - controller.displayContactPermissionDialog(context), - ), - ); - } -} - -class _Contact extends StatelessWidget { - const _Contact({required this.contact, required this.controller}); - - final PresentationContact contact; - final ContactsTabController controller; - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric( - horizontal: ContactsTabViewStyle.padding, - ), - child: ExpansionContactListTile( - contact: contact, - highlightKeyword: controller.textEditingController.text, - enableInvitation: controller.supportInvitation(), - onContactTap: () => controller.onContactTap( - context: context, - path: 'rooms', - contact: contact, - ), - ), - ); - } -} - -class _PhonebookContact extends StatelessWidget { - const _PhonebookContact({required this.contact, required this.controller}); - - final PresentationContact contact; - final ContactsTabController controller; - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric( - horizontal: ContactsTabViewStyle.padding, - ), - child: ExpansionPhonebookContactListTile( - contact: contact, - highlightKeyword: controller.textEditingController.text, - enableInvitation: controller.supportInvitation(), - onContactTap: () => controller.onContactTap( - context: context, - path: 'rooms', - contact: contact, + SliverPhonebookContactsWithMatrixId(controller: controller), + SliverContactsWithoutMatrixId(controller: controller), + if (PlatformInfos.isMobile) + SliverPhonebookContactsWithoutMatrixId(controller: controller), + SliverEmptyContacts(controller: controller), + const SliverToBoxAdapter( + child: SizedBox(height: ContactsTabViewStyle.padding), ), - ), + ], ); } } diff --git a/lib/pages/contacts_tab/widgets/sliver_contacts_with_matrix_id.dart b/lib/pages/contacts_tab/widgets/sliver_contacts_with_matrix_id.dart new file mode 100644 index 0000000000..e8df922ee0 --- /dev/null +++ b/lib/pages/contacts_tab/widgets/sliver_contacts_with_matrix_id.dart @@ -0,0 +1,119 @@ +import 'package:fluffychat/domain/app_state/contact/get_contacts_state.dart'; +import 'package:fluffychat/pages/contacts_tab/contacts_tab.dart'; +import 'package:fluffychat/pages/contacts_tab/contacts_tab_view_style.dart'; +import 'package:fluffychat/pages/new_private_chat/widget/expansion_contact_list_tile.dart'; +import 'package:fluffychat/presentation/model/contact/presentation_contact.dart'; +import 'package:fluffychat/presentation/model/contact/presentation_contact_success.dart'; +import 'package:fluffychat/utils/platform_infos.dart'; +import 'package:fluffychat/widgets/sliver_expandable_list.dart'; +import 'package:flutter/material.dart'; +import 'package:fluffychat/generated/l10n/app_localizations.dart'; + +class SliverContactsWithMatrixId extends StatelessWidget { + const SliverContactsWithMatrixId({required this.controller, super.key}); + + final ContactsTabController controller; + + @override + Widget build(BuildContext context) { + const empty = SliverToBoxAdapter(); + return ValueListenableBuilder( + valueListenable: controller.presentationContactNotifier, + builder: (context, state, _) { + return state.fold((_) => empty, (success) { + if (success is ContactsLoading) { + return empty; + } + + if (success is PresentationExternalContactSuccess) { + if (controller.presentationRecentContactNotifier.value.isNotEmpty) { + return empty; + } + if (!PlatformInfos.isWeb) { + if (controller.phoneBookFilterSuccess) { + return empty; + } + } + return _ExternalContactTile( + controller: controller, + contact: success.contact, + ); + } + + if (success is PresentationContactsSuccess) { + final contacts = success.contacts + .where((c) => c.matrixId != null && c.matrixId!.isNotEmpty) + .toList(); + if (contacts.isEmpty) { + return empty; + } + return SliverExpandableList( + title: L10n.of(context)!.linagoraContactsCount(contacts.length), + itemCount: contacts.length, + itemBuilder: (context, index) => _ContactTile( + contact: contacts[index], + controller: controller, + ), + ); + } + + return empty; + }); + }, + ); + } +} + +class _ExternalContactTile extends StatelessWidget { + const _ExternalContactTile({required this.controller, required this.contact}); + + final ContactsTabController controller; + final PresentationContact contact; + + @override + Widget build(BuildContext context) { + return SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: ContactsTabViewStyle.padding, + ), + child: ExpansionContactListTile( + contact: contact, + highlightKeyword: controller.textEditingController.text, + enableInvitation: controller.supportInvitation(), + onContactTap: () => controller.onContactTap( + context: context, + path: 'rooms', + contact: contact, + ), + ), + ), + ); + } +} + +class _ContactTile extends StatelessWidget { + const _ContactTile({required this.contact, required this.controller}); + + final PresentationContact contact; + final ContactsTabController controller; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: ContactsTabViewStyle.padding, + ), + child: ExpansionContactListTile( + contact: contact, + highlightKeyword: controller.textEditingController.text, + enableInvitation: controller.supportInvitation(), + onContactTap: () => controller.onContactTap( + context: context, + path: 'rooms', + contact: contact, + ), + ), + ); + } +} diff --git a/lib/pages/contacts_tab/widgets/sliver_contacts_without_matrix_id.dart b/lib/pages/contacts_tab/widgets/sliver_contacts_without_matrix_id.dart new file mode 100644 index 0000000000..42f9b9371a --- /dev/null +++ b/lib/pages/contacts_tab/widgets/sliver_contacts_without_matrix_id.dart @@ -0,0 +1,75 @@ +import 'package:fluffychat/domain/app_state/contact/get_contacts_state.dart'; +import 'package:fluffychat/pages/contacts_tab/contacts_tab.dart'; +import 'package:fluffychat/pages/contacts_tab/contacts_tab_view_style.dart'; +import 'package:fluffychat/pages/new_private_chat/widget/expansion_contact_list_tile.dart'; +import 'package:fluffychat/presentation/model/contact/presentation_contact.dart'; +import 'package:fluffychat/presentation/model/contact/presentation_contact_success.dart'; +import 'package:fluffychat/widgets/sliver_expandable_list.dart'; +import 'package:flutter/material.dart'; +import 'package:fluffychat/generated/l10n/app_localizations.dart'; + +class SliverContactsWithoutMatrixId extends StatelessWidget { + const SliverContactsWithoutMatrixId({required this.controller, super.key}); + + final ContactsTabController controller; + + @override + Widget build(BuildContext context) { + const empty = SliverToBoxAdapter(); + return ValueListenableBuilder( + valueListenable: controller.presentationContactNotifier, + builder: (context, state, _) { + return state.fold((_) => empty, (success) { + if (success is ContactsLoading) { + return empty; + } + + if (success is PresentationContactsSuccess) { + final contacts = success.contacts + .where((c) => c.matrixId == null || c.matrixId!.isEmpty) + .toList(); + if (contacts.isEmpty) { + return empty; + } + return SliverExpandableList( + title: L10n.of(context)!.linagoraContactsCount(contacts.length), + itemCount: contacts.length, + itemBuilder: (context, index) => _ContactTile( + contact: contacts[index], + controller: controller, + ), + ); + } + + return empty; + }); + }, + ); + } +} + +class _ContactTile extends StatelessWidget { + const _ContactTile({required this.contact, required this.controller}); + + final PresentationContact contact; + final ContactsTabController controller; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: ContactsTabViewStyle.padding, + ), + child: ExpansionContactListTile( + contact: contact, + highlightKeyword: controller.textEditingController.text, + enableInvitation: controller.supportInvitation(), + onContactTap: () => controller.onContactTap( + context: context, + path: 'rooms', + contact: contact, + ), + ), + ); + } +} diff --git a/lib/pages/contacts_tab/widgets/sliver_empty_contacts.dart b/lib/pages/contacts_tab/widgets/sliver_empty_contacts.dart new file mode 100644 index 0000000000..f1b2a7411e --- /dev/null +++ b/lib/pages/contacts_tab/widgets/sliver_empty_contacts.dart @@ -0,0 +1,66 @@ +import 'package:fluffychat/domain/app_state/contact/get_contacts_state.dart'; +import 'package:fluffychat/pages/contacts_tab/contacts_tab.dart'; +import 'package:fluffychat/pages/contacts_tab/contacts_tab_view_style.dart'; +import 'package:fluffychat/pages/contacts_tab/empty_contacts_body.dart'; +import 'package:fluffychat/pages/new_private_chat/widget/no_contacts_found.dart'; +import 'package:fluffychat/presentation/model/contact/presentation_contact_success.dart'; +import 'package:flutter/material.dart'; + +class SliverEmptyContacts extends StatelessWidget { + const SliverEmptyContacts({required this.controller, super.key}); + + final ContactsTabController controller; + + bool _isLoading() => controller.presentationContactNotifier.value.fold( + (_) => false, + (s) => s is ContactsLoading, + ); + + bool _hasContactsData() => controller.presentationContactNotifier.value.fold( + (_) => false, + (s) => + (s is PresentationContactsSuccess && s.contacts.isNotEmpty) || + s is PresentationExternalContactSuccess, + ); + + bool _hasPhonebookData() => + controller.presentationPhonebookContactNotifier.value.fold( + (_) => false, + (s) => s is PresentationContactsSuccess && s.contacts.isNotEmpty, + ); + + bool _hasRecentData() => + controller.presentationRecentContactNotifier.value.isNotEmpty; + + @override + Widget build(BuildContext context) { + return ListenableBuilder( + listenable: Listenable.merge([ + controller.presentationContactNotifier, + controller.presentationPhonebookContactNotifier, + controller.presentationRecentContactNotifier, + ]), + builder: (context, _) { + if (_isLoading() || + _hasContactsData() || + _hasPhonebookData() || + _hasRecentData()) { + return const SliverToBoxAdapter(); + } + final keyword = controller.textEditingController.text; + if (keyword.isEmpty) { + return const SliverToBoxAdapter(child: EmptyContactBody()); + } + return SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.only( + left: ContactsTabViewStyle.padding, + top: ContactsTabViewStyle.padding, + ), + child: NoContactsFound(keyword: keyword), + ), + ); + }, + ); + } +} diff --git a/lib/pages/contacts_tab/widgets/sliver_loading_contacts.dart b/lib/pages/contacts_tab/widgets/sliver_loading_contacts.dart new file mode 100644 index 0000000000..db38ff1311 --- /dev/null +++ b/lib/pages/contacts_tab/widgets/sliver_loading_contacts.dart @@ -0,0 +1,25 @@ +import 'package:fluffychat/domain/app_state/contact/get_contacts_state.dart'; +import 'package:fluffychat/pages/contacts_tab/contacts_tab.dart'; +import 'package:fluffychat/pages/new_private_chat/widget/loading_contact_widget.dart'; +import 'package:flutter/material.dart'; + +class SliverLoadingContacts extends StatelessWidget { + const SliverLoadingContacts({required this.controller, super.key}); + + final ContactsTabController controller; + + @override + Widget build(BuildContext context) { + return ValueListenableBuilder( + valueListenable: controller.presentationContactNotifier, + builder: (context, state, _) { + return state.fold((_) => const SliverToBoxAdapter(), (success) { + if (success is ContactsLoading) { + return const SliverToBoxAdapter(child: LoadingContactWidget()); + } + return const SliverToBoxAdapter(); + }); + }, + ); + } +} diff --git a/lib/pages/contacts_tab/widgets/sliver_phonebook_contacts_with_matrix_id.dart b/lib/pages/contacts_tab/widgets/sliver_phonebook_contacts_with_matrix_id.dart new file mode 100644 index 0000000000..f276572465 --- /dev/null +++ b/lib/pages/contacts_tab/widgets/sliver_phonebook_contacts_with_matrix_id.dart @@ -0,0 +1,75 @@ +import 'package:fluffychat/pages/contacts_tab/contacts_tab.dart'; +import 'package:fluffychat/pages/contacts_tab/contacts_tab_view_style.dart'; +import 'package:fluffychat/pages/new_private_chat/widget/expansion_phonebook_contact_list_tile.dart'; +import 'package:fluffychat/presentation/model/contact/presentation_contact.dart'; +import 'package:fluffychat/presentation/model/contact/presentation_contact_success.dart'; +import 'package:fluffychat/widgets/sliver_expandable_list.dart'; +import 'package:flutter/material.dart'; +import 'package:fluffychat/generated/l10n/app_localizations.dart'; + +class SliverPhonebookContactsWithMatrixId extends StatelessWidget { + const SliverPhonebookContactsWithMatrixId({ + required this.controller, + super.key, + }); + + final ContactsTabController controller; + + @override + Widget build(BuildContext context) { + const empty = SliverToBoxAdapter(); + return ValueListenableBuilder( + valueListenable: controller.presentationPhonebookContactNotifier, + builder: (context, state, _) { + return state.fold((_) => empty, (success) { + if (success is PresentationContactsSuccess) { + final contacts = success.contacts + .where((c) => c.matrixId != null && c.matrixId!.isNotEmpty) + .toList(); + if (contacts.isEmpty) { + return empty; + } + return SliverExpandableList( + title: L10n.of(context)!.contactsCount(contacts.length), + itemCount: contacts.length, + itemBuilder: (context, index) => _PhonebookContactTile( + contact: contacts[index], + controller: controller, + ), + ); + } + return empty; + }); + }, + ); + } +} + +class _PhonebookContactTile extends StatelessWidget { + const _PhonebookContactTile({ + required this.contact, + required this.controller, + }); + + final PresentationContact contact; + final ContactsTabController controller; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: ContactsTabViewStyle.padding, + ), + child: ExpansionPhonebookContactListTile( + contact: contact, + highlightKeyword: controller.textEditingController.text, + enableInvitation: controller.supportInvitation(), + onContactTap: () => controller.onContactTap( + context: context, + path: 'rooms', + contact: contact, + ), + ), + ); + } +} diff --git a/lib/pages/contacts_tab/widgets/sliver_phonebook_contacts_without_matrix_id.dart b/lib/pages/contacts_tab/widgets/sliver_phonebook_contacts_without_matrix_id.dart new file mode 100644 index 0000000000..96a011a4fb --- /dev/null +++ b/lib/pages/contacts_tab/widgets/sliver_phonebook_contacts_without_matrix_id.dart @@ -0,0 +1,75 @@ +import 'package:fluffychat/pages/contacts_tab/contacts_tab.dart'; +import 'package:fluffychat/pages/contacts_tab/contacts_tab_view_style.dart'; +import 'package:fluffychat/pages/new_private_chat/widget/expansion_phonebook_contact_list_tile.dart'; +import 'package:fluffychat/presentation/model/contact/presentation_contact.dart'; +import 'package:fluffychat/presentation/model/contact/presentation_contact_success.dart'; +import 'package:fluffychat/widgets/sliver_expandable_list.dart'; +import 'package:flutter/material.dart'; +import 'package:fluffychat/generated/l10n/app_localizations.dart'; + +class SliverPhonebookContactsWithoutMatrixId extends StatelessWidget { + const SliverPhonebookContactsWithoutMatrixId({ + required this.controller, + super.key, + }); + + final ContactsTabController controller; + + @override + Widget build(BuildContext context) { + const empty = SliverToBoxAdapter(); + return ValueListenableBuilder( + valueListenable: controller.presentationPhonebookContactNotifier, + builder: (context, state, _) { + return state.fold((_) => empty, (success) { + if (success is PresentationContactsSuccess) { + final contacts = success.contacts + .where((c) => c.matrixId == null || c.matrixId!.isEmpty) + .toList(); + if (contacts.isEmpty) { + return empty; + } + return SliverExpandableList( + title: L10n.of(context)!.contactsCount(contacts.length), + itemCount: contacts.length, + itemBuilder: (context, index) => _PhonebookContactTile( + contact: contacts[index], + controller: controller, + ), + ); + } + return empty; + }); + }, + ); + } +} + +class _PhonebookContactTile extends StatelessWidget { + const _PhonebookContactTile({ + required this.contact, + required this.controller, + }); + + final PresentationContact contact; + final ContactsTabController controller; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: ContactsTabViewStyle.padding, + ), + child: ExpansionPhonebookContactListTile( + contact: contact, + highlightKeyword: controller.textEditingController.text, + enableInvitation: controller.supportInvitation(), + onContactTap: () => controller.onContactTap( + context: context, + path: 'rooms', + contact: contact, + ), + ), + ); + } +} diff --git a/lib/pages/contacts_tab/widgets/sliver_recent_contacts.dart b/lib/pages/contacts_tab/widgets/sliver_recent_contacts.dart new file mode 100644 index 0000000000..c8b46534f5 --- /dev/null +++ b/lib/pages/contacts_tab/widgets/sliver_recent_contacts.dart @@ -0,0 +1,59 @@ +import 'package:fluffychat/domain/app_state/contact/get_contacts_state.dart'; +import 'package:fluffychat/pages/contacts_tab/contacts_tab.dart'; +import 'package:fluffychat/pages/contacts_tab/contacts_tab_view_style.dart'; +import 'package:fluffychat/pages/search/recent_item_widget.dart'; +import 'package:fluffychat/presentation/model/search/presentation_search.dart'; +import 'package:fluffychat/widgets/sliver_expandable_list.dart'; +import 'package:flutter/material.dart'; +import 'package:fluffychat/generated/l10n/app_localizations.dart'; + +class SliverRecentContacts extends StatelessWidget { + const SliverRecentContacts({required this.controller, super.key}); + + final ContactsTabController controller; + + @override + Widget build(BuildContext context) { + return ValueListenableBuilder( + valueListenable: controller.presentationContactNotifier, + builder: (context, state, child) { + return state.fold((_) => child!, (success) { + if (success is ContactsLoading) { + return const SliverToBoxAdapter(); + } + return child!; + }); + }, + child: ValueListenableBuilder( + valueListenable: controller.presentationRecentContactNotifier, + builder: (context, recentContacts, child) { + if (recentContacts.isEmpty) { + return child!; + } + return SliverExpandableList( + title: L10n.of(context)!.recent, + itemCount: recentContacts.length, + itemBuilder: (context, index) => Padding( + padding: const EdgeInsets.symmetric( + horizontal: ContactsTabViewStyle.padding, + ), + child: RecentItemWidget( + presentationSearch: recentContacts[index], + highlightKeyword: controller.textEditingController.text, + client: controller.client, + key: Key('contact_recent_${recentContacts[index].id}'), + onTap: () => controller.onContactTap( + contact: recentContacts[index].toPresentationContact(), + context: context, + path: 'rooms', + ), + avatarSize: ContactsTabViewStyle.avatarSize, + ), + ), + ); + }, + child: const SliverToBoxAdapter(), + ), + ); + } +} diff --git a/lib/pages/contacts_tab/widgets/sliver_warning_banner.dart b/lib/pages/contacts_tab/widgets/sliver_warning_banner.dart new file mode 100644 index 0000000000..89f3ee6b75 --- /dev/null +++ b/lib/pages/contacts_tab/widgets/sliver_warning_banner.dart @@ -0,0 +1,21 @@ +import 'package:fluffychat/pages/contacts_tab/contacts_tab.dart'; +import 'package:fluffychat/widgets/contacts_warning_banner/contacts_warning_banner_view.dart'; +import 'package:flutter/material.dart'; + +class SliverWarningBanner extends StatelessWidget { + const SliverWarningBanner({required this.controller, super.key}); + + final ContactsTabController controller; + + @override + Widget build(BuildContext context) { + return SliverToBoxAdapter( + child: ContactsWarningBannerView( + warningBannerNotifier: controller.warningBannerNotifier, + closeContactsWarningBanner: controller.closeContactsWarningBanner, + goToSettingsForPermissionActions: () => + controller.displayContactPermissionDialog(context), + ), + ); + } +}