From de870b6c45ef5731203e3f862d9cbc0d2fd52663 Mon Sep 17 00:00:00 2001 From: Ameera Sherin <89637967+Ameera-Sherin@users.noreply.github.com> Date: Tue, 25 Jun 2024 13:32:59 +0530 Subject: [PATCH] feat: Add tabs in the inbox --- .github/workflows/publish.yml | 119 ++++ .gitignore | 2 +- CHANGELOG.md | 13 +- README.md | 2 + env | 2 +- example/pubspec.lock | 2 +- lib/src/api/fetch_all_notification.dart | 4 + lib/src/api/notifications_bulk_update.dart | 6 +- lib/src/constants/generics.dart | 14 + lib/src/constants/strings.dart | 3 + lib/src/models/notification_model.dart | 9 +- lib/src/models/ui_models.dart | 105 +++- lib/src/theme/app_colors.dart | 4 + lib/src/theme/dark_colors.dart | 2 + lib/src/theme/light_colors.dart | 2 + lib/src/widgets/app_bar.dart | 16 +- lib/src/widgets/card.dart | 5 +- lib/src/widgets/empty_widget.dart | 5 +- lib/src/widgets/inbox_body.dart | 8 +- lib/src/widgets/loader_widget.dart | 2 +- lib/src/widgets/siren_inbox.dart | 523 ++++++++++------ pub_login.sh | 28 + pubspec.lock | 581 ++++++++++++++++++ pubspec.yaml | 10 +- test/constants/generics_test.dart | 11 + test/data/siren_data_provider_test.mocks.dart | 7 +- test/models/notification_model_test.dart | 20 +- test/models/ui_models_test.dart | 77 +++ test/services/api_client_test.mocks.dart | 92 ++- test/services/network_service_test.mocks.dart | 8 +- test/utils/siren_test.dart | 122 ++-- test/widgets/card_test.dart | 2 +- test/widgets/empty_widget_test.dart | 8 +- test/widgets/inbox_body_test.dart | 5 +- test/widgets/notification_list_view_test.dart | 2 +- test/widgets/siren_inbox_icon_test.mocks.dart | 55 +- test/widgets/siren_inbox_test.dart | 12 + test/widgets/siren_inbox_test.mocks.dart | 72 ++- 38 files changed, 1628 insertions(+), 332 deletions(-) create mode 100644 .github/workflows/publish.yml create mode 100644 pub_login.sh create mode 100644 pubspec.lock diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..9f3e4d7 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,119 @@ +name: Publish sirenapp_flutter_inbox in pub.dev + +on: + workflow_dispatch: + inputs: + ReleaseType: + description: 'Release Type' + required: true + default: 'Patch' + type: choice + options: + - "Major" + - "Minor" + - "Patch" + + +jobs: + publish: + permissions: + id-token: write # Required for authentication using OIDC + contents: write + runs-on: ubuntu-latest + steps: + - name: Get branch names. + id: branch-names + uses: tj-actions/branch-names@v8 + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Git + run: | + git config user.name github-actions + git config user.email github-actions@github.com + export BRANCH=${{ steps.branch-names.outputs.current_branch }} + echo "branch: $BRANCH" + if [[ "$BRANCH" != "master" ]]; then + echo "Tagging cannot be done on a branch other than master" + echo $BRANCH + exit 1 + fi + export VERSION=$(cat pubspec.yaml | grep "version:" | awk '{print $2}' | sed 's/^[ \t]*//;s/[ \t]*$//') + echo $VERSION + export UPDATE_CHOICE=${{ inputs.ReleaseType }} + export MAJOR=$(echo $VERSION | cut -d. -f1) + export MINOR=$(echo $VERSION | cut -d. -f2) + export PATCH=$(echo $VERSION | cut -d"+" -f1 | cut -d"." -f3) + if [[ "$UPDATE_CHOICE" == "Major" ]]; then export NEW_TAG=$((MAJOR + 1)).0.0; fi + if [[ "$UPDATE_CHOICE" == "Minor" ]]; then export NEW_TAG=$MAJOR.$((MINOR + 1)).0; fi + if [[ "$UPDATE_CHOICE" == "Patch" ]]; then export NEW_TAG=$MAJOR.$MINOR.$((PATCH + 1)); fi + echo NEW_TAG $NEW_TAG + echo "NEW_TAG=$NEW_TAG" >> $GITHUB_ENV + sed -i "s/version: $VERSION/version: $NEW_TAG/g" pubspec.yaml + + - uses: actions/setup-java@v1 + with: + java-version: '12.x' + - uses: subosito/flutter-action@v1 + with: + channel: 'stable' + + - name: Exclude Example application + run: rm -rf example + + - name: Install dependencies + run: flutter pub get + + - name: Analyze project source + run: flutter analyze lib/ + + - name: Run tests + run: flutter test lib/ + + - name: Setup Pub Credentials + shell: bash + env: + INPUT_ACCESS_TOKEN: ${{ secrets.INPUT_ACCESS_TOKEN }} + INPUT_REFRESH_TOKEN: ${{ secrets.INPUT_REFRESH_TOKEN }} + run: | + sh ./pub_login.sh + + - name: Check Publish Warnings + run: flutter pub publish --dry-run + + - name: Publish Package + run: flutter pub publish -f + + - name: Commit pubspec.yaml + if: success() + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NEW_TAG: ${{ env.NEW_TAG }} + run: | + git add pubspec.yaml + git commit -m "Version bumped to $NEW_TAG" + git push origin $BRANCH + + - name: Create New Tag + if: success() + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NEW_TAG: ${{ env.NEW_TAG }} + run: | + git tag v${{ env.NEW_TAG }} + git push origin v${{ env.NEW_TAG }} + + + - name: Create GitHub release + if: success() + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NEW_TAG: ${{ env.NEW_TAG }} + with: + tag_name: v${{ env.NEW_TAG }} + release_name: Release v${{ env.NEW_TAG }} + draft: false + prerelease: false + diff --git a/.gitignore b/.gitignore index f0e8934..e9d6a12 100644 --- a/.gitignore +++ b/.gitignore @@ -24,8 +24,8 @@ migrate_working_dir/ # Flutter/Dart/Pub related # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. -/pubspec.lock **/doc/api/ .dart_tool/ build/ coverage/ + diff --git a/CHANGELOG.md b/CHANGELOG.md index 2695459..78c841a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to this project will be documented in this file. +## 1.2.0 + +### Added +- Support for tab-based categorization, tabular styles and formats exposure. + + ## 1.1.0 ### Added @@ -15,9 +21,4 @@ All notable changes to this project will be documented in this file. This is the first public release of the package. ### Added -- Flutter UI kit for displaying and managing in-app notifications. - - - - - +- Flutter UI kit for displaying and managing in-app notifications. \ No newline at end of file diff --git a/README.md b/README.md index 7eda372..6745f4f 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,7 @@ Given below are the arguments of Siren Inbox Widget. | Arguments | Description | Type | Default value | | ----------------- | -------------------------------------------------------------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | darkMode | Toggle to enable dark mode when custom theme is not passed | bool | false | +| hideTab | Toggle to enable all and unread tabs | bool | false | | itemsPerFetch | Number of notifications fetch per api request (have a max cap of 50) | int | 20 | | listEmptyWidget | Custom widget for empty notification list | Widget | null | | customCard | Custom widget to display the notification cards | Widget | null | @@ -108,6 +109,7 @@ Given below are the arguments of Siren Inbox Widget. | customErrorWidget | Custom error widget | Widget | null | | cardParams | Properties of notification card | CardParams | CardParams(hideAvatar: false, disableAutoMarkAsRead: false, hideDelete: false, deleteIcon: Icon(Icons.close), onAvatarClick: Function(NotificationType), hideMediaThumbnail: false, onMediaThumbnailClick: Function(NotificationType)) | | headerParams | Properties of notification window header | HeaderParams | HeaderParams(hideHeader: false, hideClearAll: false,title: 'Notifications', customHeader: null showBackButton:false, backButton: null, onBackPress: ()=> null ) | +| tabParams | Properties of tab bar | TabParams | TabParams(tabs: [TabItem(key: 'ALL', title: 'All'), TabItem(key: 'UNREAD', title: 'Unread')], activeTabIndex:0,) | | onCardClick | Custom click handler for notification cards | Function(NotificationType) | null | | onError | Callback for handling errors | Function(SirenErrorType) | null | | theme | Theme properties for custom color theme | CustomThemeColors | null | diff --git a/env b/env index b8ede4b..77317ce 100644 --- a/env +++ b/env @@ -1 +1 @@ -API_DOMAIN = https://api.sirenapp.io/api/ \ No newline at end of file +API_DOMAIN = https://api.trysiren.io/api/ \ No newline at end of file diff --git a/example/pubspec.lock b/example/pubspec.lock index b68ab16..a4e44bf 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -169,7 +169,7 @@ packages: path: ".." relative: true source: path - version: "1.0.0" + version: "1.1.0" sky_engine: dependency: transitive description: flutter diff --git a/lib/src/api/fetch_all_notification.dart b/lib/src/api/fetch_all_notification.dart index 74b1527..584a393 100644 --- a/lib/src/api/fetch_all_notification.dart +++ b/lib/src/api/fetch_all_notification.dart @@ -49,6 +49,10 @@ class FetchAllNotifications { queryParams['start'] = start; } + if (isRead != null) { + queryParams['isRead'] = isRead.toString(); + } + final queryString = queryParams.entries.map((e) => '${e.key}=${e.value}').join('&'); diff --git a/lib/src/api/notifications_bulk_update.dart b/lib/src/api/notifications_bulk_update.dart index 3505d41..de1f796 100644 --- a/lib/src/api/notifications_bulk_update.dart +++ b/lib/src/api/notifications_bulk_update.dart @@ -17,10 +17,14 @@ class NotificationsBulkUpdate { Future notificationsBulkUpdate({ required Map data, required String operation, + bool? isRead, }) async { final api = ApiClient(apiProvider()); - final apiPath = + var apiPath = '${Generics.V2}${Generics.BASE_URL}${SirenDataProvider.instance.recipientId}/notifications/bulk-update'; + if (isRead != null) { + apiPath = '$apiPath?isRead=$isRead'; + } final result = ApiResponse()..isLoading; var apiError = Errors.markAsReadFailedError; diff --git a/lib/src/constants/generics.dart b/lib/src/constants/generics.dart index 25a7282..5b324c9 100644 --- a/lib/src/constants/generics.dart +++ b/lib/src/constants/generics.dart @@ -1,3 +1,6 @@ +import 'package:sirenapp_flutter_inbox/src/constants/strings.dart'; +import 'package:sirenapp_flutter_inbox/src/models/ui_models.dart'; + class Generics { Generics._(); @@ -9,6 +12,15 @@ class Generics { static const int AVERAGE_ITEMS_ON_SCREEN = 7; static const int MAX_RETRIES = 2; static const String ENV_PATH = 'packages/sirenapp_flutter_inbox/env'; + + static final inboxTabs = [ + TabItem(key: InboxTabs.ALL.name, title: Strings.tabAll), + TabItem(key: InboxTabs.UNREAD.name, title: Strings.tabUnread), + ]; + static final List emptyMessages = [ + Strings.empty_title, + Strings.empty_title_unread, + ]; } enum Status { @@ -19,6 +31,8 @@ enum Status { INVALID_CREDENTIALS, } +enum InboxTabs { ALL, UNREAD } + enum BulkUpdateType { MARK_AS_READ, MARK_AS_DELETED, diff --git a/lib/src/constants/strings.dart b/lib/src/constants/strings.dart index f334f53..41bfe3e 100644 --- a/lib/src/constants/strings.dart +++ b/lib/src/constants/strings.dart @@ -2,6 +2,7 @@ class Strings { Strings._(); static const empty_title = 'No new notifications'; + static const empty_title_unread = 'No unread notifications'; static const empty_desc = 'Check back later for updates and alerts.'; static const error_title = 'Oops! Something went wrong.'; static const something_went_wrong = 'Something went wrong'; @@ -29,4 +30,6 @@ class Strings { 'This operation require valid credentials'; static const invalidCredentialsError = 'Invalid credentials found. Please check your token and recipient ID'; + static const tabAll = 'All'; + static const tabUnread = 'Unread'; } diff --git a/lib/src/models/notification_model.dart b/lib/src/models/notification_model.dart index 9ee9bd7..68f56f7 100644 --- a/lib/src/models/notification_model.dart +++ b/lib/src/models/notification_model.dart @@ -77,7 +77,10 @@ class MessageData { thumbnailUrl: json?['thumbnailUrl'] != null ? (json?['thumbnailUrl'] as String?) : '', - additionalData: json?['additionalData'] as String?, + additionalData: + (json?['additionalData'] != null && json?['additionalData'] is Map) + ? json!['additionalData'] as Map? + : null, ); } @@ -100,9 +103,9 @@ class MessageData { final AvatarData? avatar; /// Additional data related to the message. - final String? additionalData; + final Map? additionalData; - /// The thumbnail URL associated with the message to display + /// The thumbnail URL associated with the message to display. final String? thumbnailUrl; } diff --git a/lib/src/models/ui_models.dart b/lib/src/models/ui_models.dart index a19f99a..5631392 100644 --- a/lib/src/models/ui_models.dart +++ b/lib/src/models/ui_models.dart @@ -98,6 +98,8 @@ class CustomStyles { this.timerIconStyle, this.deleteIconStyle, this.clearAllIconStyle, + this.tabStyles, + this.hideTabMargin, }); /// The decoration for the Siren inbox list. @@ -123,6 +125,20 @@ class CustomStyles { /// Style of clear all icon in inbox default header final ClearAllIconStyle? clearAllIconStyle; + + final TabStyles? tabStyles; + + final HideTabMargin? hideTabMargin; +} + +class HideTabMargin { + HideTabMargin({ + this.upper, + this.lower, + }); + + final bool? upper; + final bool? lower; } class TimerIconStyle { @@ -170,6 +186,7 @@ class CustomThemeColors { this.inboxHeaderColors, this.badgeColors, this.cardColors, + this.tabColors, }); /// The background color for Siren inbox. @@ -213,6 +230,9 @@ class CustomThemeColors { /// The colors for inbox list card final BadgeColors? badgeColors; + + /// The colors for tab bar + final TabColors? tabColors; } /// Custom theme colors to configure the appearance inbox list item. @@ -313,7 +333,7 @@ class HeaderParams { /// Properties to configure the style of container class ContainerStyle { - ContainerStyle({this.padding, this.decoration}); + ContainerStyle({this.padding, this.decoration, this.margin}); /// The padding values for all sides of a container final EdgeInsetsGeometry? padding; @@ -321,6 +341,9 @@ class ContainerStyle { /// The appearance of the container, including /// properties like background color, border, border radius, etc. of a container final BoxDecoration? decoration; + + /// The margin values for all sides of a container + final EdgeInsetsGeometry? margin; } /// Properties to configure the style of default inbox header @@ -365,3 +388,83 @@ class CardStyle { /// The size of avatar image final double? avatarSize; } + +/// Properties for configuring the appearance and behavior of the tab bar. +class TabParams { + /// Constructs a [TabParams] with optional parameters. + TabParams({ + this.activeTabIndex, + this.tabs, + }); + + /// The index of the initial active tab. + final int? activeTabIndex; + + /// The list of tab items. + final List? tabs; +} + +/// Represents an individual tab item. +class TabItem { + TabItem({ + required this.key, + required this.title, + }); + + /// The unique key for the tab item. + final String key; + + /// The title of the tab item. + final String title; +} + +/// Styles for customizing the appearance of the tab bar. +class TabStyles { + TabStyles({ + this.containerStyle, + this.activeTabTextStyle, + this.inActiveTabTextStyle, + this.indicatorSize, + this.indicatorPadding, + }); + + /// The tab bar container style + final ContainerStyle? containerStyle; + + /// The height of the indicator + final double? indicatorSize; + + /// The text style for the active tab. + final TextStyle? activeTabTextStyle; + + /// The text style for the inactive tab. + final TextStyle? inActiveTabTextStyle; + + final EdgeInsetsGeometry? indicatorPadding; +} + +/// Colors for customizing the appearance of the tab bar. +class TabColors { + TabColors({ + this.containerBackgroundColor, + this.activeTabBackgroundColor, + this.activeTabTextColor, + this.inactiveTabTextColor, + this.indicatorColor, + }); + + /// The background color of the tab bar container. + final Color? containerBackgroundColor; + + /// The background color of the active tab. + final Color? activeTabBackgroundColor; + + /// The text color of the active tab. + final Color? activeTabTextColor; + + /// The text color of the inactive tab. + final Color? inactiveTabTextColor; + + /// The color of the tab indicator. + final Color? indicatorColor; +} diff --git a/lib/src/theme/app_colors.dart b/lib/src/theme/app_colors.dart index 78730ac..02e95f3 100644 --- a/lib/src/theme/app_colors.dart +++ b/lib/src/theme/app_colors.dart @@ -40,6 +40,8 @@ class AppColors { required this.primary, required this.scaffoldBackgroundColor, required this.skeletonLoaderColor, + required this.tabBarActiveColor, + required this.tabBarInActiveColor, required this.textColor, required this.timerIcon, }); @@ -83,6 +85,8 @@ class AppColors { Color primary; Color scaffoldBackgroundColor; Color skeletonLoaderColor; + Color tabBarActiveColor; + Color tabBarInActiveColor; Color textColor; Color timerIcon; } diff --git a/lib/src/theme/dark_colors.dart b/lib/src/theme/dark_colors.dart index 8ac18fa..387fd93 100644 --- a/lib/src/theme/dark_colors.dart +++ b/lib/src/theme/dark_colors.dart @@ -39,6 +39,8 @@ final darkColors = AppColors( primary: SirenAppColors.primary200Complementary, scaffoldBackgroundColor: SirenAppColors.black100, skeletonLoaderColor: SirenAppColors.avatarPlaceholderBgDark, + tabBarActiveColor: SirenAppColors.primary400, + tabBarInActiveColor: SirenAppColors.grey300, textColor: SirenAppColors.grey700Complementary, timerIcon: SirenAppColors.grey400, ); diff --git a/lib/src/theme/light_colors.dart b/lib/src/theme/light_colors.dart index 9c9e622..17eb429 100644 --- a/lib/src/theme/light_colors.dart +++ b/lib/src/theme/light_colors.dart @@ -39,6 +39,8 @@ final lightColors = AppColors( primary: SirenAppColors.primary200, scaffoldBackgroundColor: Colors.white, skeletonLoaderColor: SirenAppColors.avatarPlaceholderBgLight, + tabBarActiveColor: SirenAppColors.primary400, + tabBarInActiveColor: SirenAppColors.grey700, textColor: SirenAppColors.grey700, timerIcon: SirenAppColors.grey500, ); diff --git a/lib/src/widgets/app_bar.dart b/lib/src/widgets/app_bar.dart index c8709eb..5f8db01 100644 --- a/lib/src/widgets/app_bar.dart +++ b/lib/src/widgets/app_bar.dart @@ -37,13 +37,15 @@ class SirenAppBar extends StatelessWidget implements PreferredSizeWidget { decoration: BoxDecoration( color: colors?.inboxHeaderColors?.background ?? defaultColors.backgroundColor, - border: Border( - bottom: BorderSide( - width: styles?.appBarStyle?.borderWidth ?? 1, - color: colors?.inboxHeaderColors?.borderColor ?? - defaultColors.appBarBorderColor, - ), - ), + border: styles?.hideTabMargin?.upper != true + ? Border( + bottom: BorderSide( + width: styles?.appBarStyle?.borderWidth ?? 1, + color: colors?.inboxHeaderColors?.borderColor ?? + defaultColors.appBarBorderColor, + ), + ) + : null, ), height: preferredSize.height, child: Padding( diff --git a/lib/src/widgets/card.dart b/lib/src/widgets/card.dart index 7f3f5e0..fb2ce4e 100644 --- a/lib/src/widgets/card.dart +++ b/lib/src/widgets/card.dart @@ -72,7 +72,7 @@ class _CardWidgetState extends State { ) ?? _getDefaultContainerDecoration(widget.colors, defaultColors), padding: widget.styles?.cardStyle?.cardContainer?.padding ?? - const EdgeInsets.symmetric(vertical: 12, horizontal: 12), + const EdgeInsets.symmetric(vertical: 12, horizontal: 18), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -154,7 +154,6 @@ class _CardWidgetState extends State { child: Padding( padding: const EdgeInsets.only( right: 6, - left: 6, ), child: CircleAvatar( radius: widget.styles?.cardStyle?.avatarSize ?? 21, @@ -279,7 +278,7 @@ class _CardWidgetState extends State { }, child: Container( height: 140, - margin: const EdgeInsets.only(right: 10), + margin: const EdgeInsets.only(right: 2), width: double.infinity, decoration: BoxDecoration( borderRadius: BorderRadius.circular(6), diff --git a/lib/src/widgets/empty_widget.dart b/lib/src/widgets/empty_widget.dart index 4c3d836..13a219e 100644 --- a/lib/src/widgets/empty_widget.dart +++ b/lib/src/widgets/empty_widget.dart @@ -1,15 +1,18 @@ import 'package:flutter/material.dart'; +import 'package:sirenapp_flutter_inbox/src/constants/generics.dart'; import 'package:sirenapp_flutter_inbox/src/constants/strings.dart'; import 'package:sirenapp_flutter_inbox/src/theme/app_colors.dart'; import 'package:sirenapp_flutter_inbox/src/theme/app_theme.dart'; class EmptyWidget extends StatelessWidget { const EmptyWidget({ + required this.activeTabIndex, this.isDarkMode, super.key, }); final bool? isDarkMode; + final int activeTabIndex; @override Widget build(BuildContext context) { @@ -28,7 +31,7 @@ class EmptyWidget extends StatelessWidget { height: 10, ), Text( - Strings.empty_title, + Generics.emptyMessages[activeTabIndex], style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, diff --git a/lib/src/widgets/inbox_body.dart b/lib/src/widgets/inbox_body.dart index b5d10f1..e36be56 100644 --- a/lib/src/widgets/inbox_body.dart +++ b/lib/src/widgets/inbox_body.dart @@ -22,6 +22,7 @@ class InboxBody extends StatelessWidget { required this.endReached, required this.onEndReached, required this.scrollController, + required this.activeTabIndex, this.customErrorWidget, this.customLoader, this.customStyles, @@ -52,6 +53,7 @@ class InboxBody extends StatelessWidget { final ScrollController scrollController; final Widget? listEmptyWidget; final bool? isDarkMode; + final int activeTabIndex; @override Widget build(BuildContext context) { @@ -93,7 +95,11 @@ class InboxBody extends StatelessWidget { label: 'siren-empty-state', hint: 'Empty notification list', key: const Key('siren-empty-state'), - child: listEmptyWidget ?? EmptyWidget(isDarkMode: isDarkMode), + child: listEmptyWidget ?? + EmptyWidget( + isDarkMode: isDarkMode, + activeTabIndex: activeTabIndex, + ), ); } else { return Container( diff --git a/lib/src/widgets/loader_widget.dart b/lib/src/widgets/loader_widget.dart index c31091b..bc13ffa 100644 --- a/lib/src/widgets/loader_widget.dart +++ b/lib/src/widgets/loader_widget.dart @@ -85,7 +85,7 @@ class CardLoaderWidgetState extends State decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), ), - padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 10), + padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 18), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/lib/src/widgets/siren_inbox.dart b/lib/src/widgets/siren_inbox.dart index ffd5712..84b12b7 100644 --- a/lib/src/widgets/siren_inbox.dart +++ b/lib/src/widgets/siren_inbox.dart @@ -21,6 +21,7 @@ class SirenInbox extends StatefulWidget { const SirenInbox({ super.key, this.darkMode, + this.hideTab, this.itemsPerFetch, this.listEmptyWidget, this.customCard, @@ -28,15 +29,20 @@ class SirenInbox extends StatefulWidget { this.customErrorWidget, this.cardParams, this.headerParams, + this.tabParams, this.onCardClick, this.onError, this.theme, this.customStyles, + this.customTabIndicator, }); /// Flag for enabling dark mode. final bool? darkMode; + /// Flag to hide the tab bar. + final bool? hideTab; + /// Notifications to be fetched in each request final int? itemsPerFetch; @@ -52,12 +58,15 @@ class SirenInbox extends StatefulWidget { /// Custom error widget. final Widget? customErrorWidget; - ///Custom props for Card properties + /// Custom properties for card. final CardParams? cardParams; - /// Custom props for header properties + /// Custom properties for inbox header. final HeaderParams? headerParams; + // Properties for the tab bar. + final TabParams? tabParams; + /// Callback function when a notification card is clicked. final void Function(NotificationType)? onCardClick; @@ -70,11 +79,14 @@ class SirenInbox extends StatefulWidget { /// Custom styles for the card of each notification. final CustomStyles? customStyles; + final BoxDecoration? customTabIndicator; + @override State createState() => _SirenInboxState(); } -class _SirenInboxState extends State { +class _SirenInboxState extends State + with SingleTickerProviderStateMixin { bool isLoading = true; bool isEndReached = false; bool isError = false; @@ -82,23 +94,22 @@ class _SirenInboxState extends State { int currentPage = 0; String? deletingNotificationId; int pageSize = 20; + int _activeTabIndex = 0; + bool _enableClearAll = true; List notifications = []; late final DeleteNotificationById _deleteNotificationById; late final ReadNotificationById _readNotificationById; late Timer? _periodicUpdateRef; late StreamSubscription _subscription; - late ScrollController _scrollController; + late ScrollController _inboxScrollController; + late List _tabScrollControllers; + late TabController _tabController; @override void initState() { super.initState(); - pageSize = max(min(widget.itemsPerFetch ?? Generics.PAGE_SIZE, 50), 0); - _periodicUpdateRef = Timer(const Duration(days: 1), () {}); - _scrollController = ScrollController(); - _scrollController.addListener(_scrollListener); - _deleteNotificationById = DeleteNotificationById.instance; - _readNotificationById = ReadNotificationById.instance; + _initializeVariables(); _subscribeToStream(); _initialize(); } @@ -106,12 +117,22 @@ class _SirenInboxState extends State { @override void dispose() { markAllNotificationsAsViewed(); - _scrollController.dispose(); + _inboxScrollController.dispose(); + for (final controller in _tabScrollControllers) { + controller.dispose(); + } + _tabController.dispose(); _periodicUpdateRef?.cancel(); _subscription.cancel(); super.dispose(); } + void safeSetState(VoidCallback callback) { + if (mounted) { + setState(callback); + } + } + Future _initialize() async { if (SirenDataProvider.instance.tokenVerificationStatus == Status.SUCCESS) { await initialFetchNotification(); @@ -119,14 +140,37 @@ class _SirenInboxState extends State { Status.FAILED || !SirenDataProvider.instance.isProviderInitialized) { widget.onError?.call(Errors.outsideSirenContextError); - if (mounted) { - setState(() { - isError = true; - }); - } + safeSetState(() { + isError = true; + }); } } + void _initializeVariables() { + pageSize = max(min(widget.itemsPerFetch ?? Generics.PAGE_SIZE, 50), 0); + _periodicUpdateRef = Timer(const Duration(days: 1), () {}); + _activeTabIndex = _activeTabIndex = (widget.tabParams?.activeTabIndex ?? 0) + .clamp(0, InboxTabs.values.length - 1); + _inboxScrollController = ScrollController(); + _inboxScrollController.addListener(_scrollListener); + _tabScrollControllers = List.generate( + InboxTabs.values.length, + (index) => ScrollController() + ..addListener(() { + _tabScrollListeners(index); + }), + ); + + _deleteNotificationById = DeleteNotificationById.instance; + _readNotificationById = ReadNotificationById.instance; + _tabController = TabController( + length: InboxTabs.values.length, + vsync: this, + initialIndex: _activeTabIndex, + ); + _tabController.addListener(_tabListener); + } + void _subscribeToStream() { _subscription = SirenDataProvider.instance.inboxController.stream.listen( (streamResponse) { @@ -134,7 +178,7 @@ class _SirenInboxState extends State { _reset(cancelFetch: true); return; } else if (streamResponse.api == UpdateEvents.SHOW_ERROR) { - setState(() { + safeSetState(() { isError = true; }); } @@ -168,69 +212,90 @@ class _SirenInboxState extends State { } void _reset({bool cancelFetch = false}) { - if (mounted) { - setState(() { - isLoading = true; - notifications = []; - isEndReached = false; - currentPage = 0; - }); - } + safeSetState(() { + isLoading = true; + notifications = []; + isEndReached = false; + currentPage = 0; + }); if (cancelFetch) { _periodicUpdateRef?.cancel(); } } - bool shouldShowClearAllButton() { - return !isError && !isLoading && notifications.isNotEmpty; - } - void _markNotificationAsReadById(String? notificationId) { - if (mounted) { - setState(() { - notifications.firstWhere((n) => n.id == notificationId).markAsRead(); - }); - } + safeSetState(() { + notifications.firstWhere((n) => n.id == notificationId).markAsRead(); + }); } void _markAllNotificationsAsRead() { - if (mounted) { - setState(() { - for (final notification in notifications) { - notification.markAsRead(); - } - }); - } + safeSetState(() { + for (final notification in notifications) { + notification.markAsRead(); + } + }); } void _deleteById(String? notificationId) { - if (mounted) { - setState(() { - notifications - .removeWhere((notification) => notification.id == notificationId); - }); - } + safeSetState(() { + notifications + .removeWhere((notification) => notification.id == notificationId); + }); } void _deleteAllNotifications() { - if (mounted) { - setState(() { - notifications = []; - }); - } + safeSetState(() { + notifications = []; + _enableClearAll = false; + }); } void _scrollListener() { - if (_scrollController.position.atEdge && - _scrollController.position.pixels == - _scrollController.position.maxScrollExtent) { + if (_inboxScrollController.position.atEdge && + _inboxScrollController.position.pixels == + _inboxScrollController.position.maxScrollExtent) { + onEndReached(); + } + } + + void _tabScrollListeners(int index) { + if (_tabScrollControllers[index].position.atEdge && + _tabScrollControllers[index].position.pixels == + _tabScrollControllers[index].position.maxScrollExtent) { onEndReached(); } } + void _tabListener() { + if (_tabController.index != _tabController.previousIndex) { + onTabChanged(_tabController.index); + } + } + + bool? getIsRead() { + if ((widget.hideTab ?? false) == false && _activeTabIndex == 1) { + return false; + } + return null; + } + + Future markAllNotificationsAsViewed() async { + final notificationsMarkedAsViewed = await MarkAllNotificationsAsViewed + .instance + .markAllNotificationsAsViewed( + untilDate: DateTime.now().toUtc().toIso8601String(), + ); + + if (notificationsMarkedAsViewed.isError) { + widget.onError?.call( + notificationsMarkedAsViewed.error ?? SirenErrorType(), + ); + } + } + void fetchNewNotifications() { - late var newNotifications = []; _periodicUpdateRef?.cancel(); _periodicUpdateRef = Timer.periodic( const Duration(seconds: Generics.DATA_FETCH_INTERVAL), @@ -238,6 +303,7 @@ class _SirenInboxState extends State { final fetchedNotifications = await FetchAllNotifications.instance.fetchAllNotifications( size: pageSize, + isRead: getIsRead(), start: notifications.isNotEmpty ? modifyAndConvertToISOString( notifications[0].createdAt, @@ -245,31 +311,20 @@ class _SirenInboxState extends State { : null, ); if (fetchedNotifications.isSuccess) { - final count = - (fetchedNotifications.data as Iterable).length; + final newNotifications = + fetchedNotifications.data as Iterable; + final count = newNotifications.length; if (count > 0) { unawaited(markAllNotificationsAsViewed()); - newNotifications.addAll( - fetchedNotifications.data as Iterable, + safeSetState( + () { + notifications.insertAll(0, newNotifications); + _enableClearAll = notifications.isNotEmpty; + if (isLoading) { + isLoading = false; + } + }, ); - if (mounted) { - setState( - () { - notifications.insertAll( - 0, - newNotifications, - ); - }, - ); - if (isLoading) { - setState( - () { - isLoading = false; - }, - ); - } - } - newNotifications = []; } } else if (fetchedNotifications.isError) { widget.onError?.call(fetchedNotifications.error ?? SirenErrorType()); @@ -278,57 +333,42 @@ class _SirenInboxState extends State { ); } - Future markAllNotificationsAsViewed() async { - final notificationsMarkedAsViewed = await MarkAllNotificationsAsViewed - .instance - .markAllNotificationsAsViewed( - untilDate: DateTime.now().toUtc().toIso8601String(), - ); - - if (notificationsMarkedAsViewed.isError) { - widget.onError?.call( - notificationsMarkedAsViewed.error ?? SirenErrorType(), - ); - } - } - Future initialFetchNotification() async { - if (mounted) { - setState(() { - isLoading = true; - }); - } + safeSetState(() { + isLoading = true; + }); + final fetchedNotifications = await FetchAllNotifications.instance.fetchAllNotifications( end: DateTime.now().toUtc().toIso8601String(), size: pageSize, + isRead: getIsRead(), ); if (fetchedNotifications.isSuccess) { unawaited(markAllNotificationsAsViewed()); - setState(() { - notifications.addAll( - fetchedNotifications.data as Iterable, - ); + safeSetState(() { + notifications + .addAll(fetchedNotifications.data as Iterable); isLoading = false; isError = false; + _enableClearAll = notifications.isNotEmpty; }); fetchNewNotifications(); } else if (fetchedNotifications.isError) { - if (mounted) { - setState(() { - isError = fetchedNotifications.isError; - }); - } + safeSetState(() { + isError = fetchedNotifications.isError; + }); + widget.onError?.call(fetchedNotifications.error ?? SirenErrorType()); } } Future onRefresh() async { if (mounted) { - _reset(); + _reset(cancelFetch: true); await initialFetchNotification(); - setState(() { + safeSetState(() { isLoading = false; }); } @@ -343,6 +383,7 @@ class _SirenInboxState extends State { await NotificationsBulkUpdate.instance.notificationsBulkUpdate( data: data, operation: BulkUpdateType.MARK_AS_DELETED.name, + isRead: getIsRead(), ); if (deleteAllResponse.isSuccess) { SirenDataProvider.instance.inboxController.sink.add( @@ -364,11 +405,9 @@ class _SirenInboxState extends State { ); if (deletionStatus.data == Status.SUCCESS && deletionStatus.isSuccess) { - if (mounted) { - setState(() { - deletingNotificationId = id; - }); - } + safeSetState(() { + deletingNotificationId = id; + }); await Future.delayed(const Duration(milliseconds: 500)); SirenDataProvider.instance.inboxController.sink.add( @@ -378,12 +417,13 @@ class _SirenInboxState extends State { id, ), ); - if (mounted) { - setState(() { - deletingNotificationId = null; - _deleteById(id); - }); - } + + _deleteById(id); + safeSetState(() { + _enableClearAll = notifications.isNotEmpty; + deletingNotificationId = null; + }); + if (notifications.length < pageSize && notifications.length < Generics.AVERAGE_ITEMS_ON_SCREEN) { onEndReached(); @@ -395,39 +435,38 @@ class _SirenInboxState extends State { void onEndReached() { if (!isLoading && !loadingNextPage && !isEndReached) { - if (mounted) { - setState(() { - loadingNextPage = true; - }); - } + safeSetState(() { + loadingNextPage = true; + }); Future.delayed(Duration.zero, () async { final fetchedNotifications = await FetchAllNotifications.instance.fetchAllNotifications( end: convertToISOString( - notifications[notifications.length - 1].createdAt, + notifications.last.createdAt, ), size: pageSize, + isRead: getIsRead(), ); if (fetchedNotifications.isSuccess) { - final count = - (fetchedNotifications.data as Iterable).length; - if (mounted) { - setState(() { - notifications.addAll( - fetchedNotifications.data as Iterable, - ); - isLoading = false; - loadingNextPage = false; - isEndReached = count < pageSize; - }); - } + final newNotifications = + fetchedNotifications.data as Iterable; + final count = newNotifications.length; + + safeSetState(() { + notifications.addAll( + newNotifications, + ); + isLoading = false; + loadingNextPage = false; + isEndReached = count < pageSize; + _enableClearAll = notifications.isNotEmpty; + }); } else if (fetchedNotifications.isError) { - if (mounted) { - setState(() { - loadingNextPage = false; - }); - } + safeSetState(() { + loadingNextPage = false; + }); + widget.onError?.call(fetchedNotifications.error ?? SirenErrorType()); } }); @@ -451,45 +490,171 @@ class _SirenInboxState extends State { } } + void onTabChanged(int index) { + if (_activeTabIndex != index) { + safeSetState(() { + _activeTabIndex = index; + _reset(cancelFetch: true); + _initialize(); + }); + } + } + + Widget _buildInboxBody( + ScrollController _controller, + List data, + bool isTabInactive, + ) { + return InboxBody( + activeTabIndex: _activeTabIndex, + cardParams: widget.cardParams, + colors: widget.theme, + customCard: widget.customCard, + customErrorWidget: widget.customErrorWidget, + customLoader: widget.customLoader, + customStyles: widget.customStyles, + deleteNotification: deleteNotification, + deletingNotificationId: deletingNotificationId, + disableAutoMarkAsRead: widget.cardParams?.disableAutoMarkAsRead ?? false, + endReached: isEndReached, + isDarkMode: widget.darkMode, + isError: isError, + isLoading: ((!(widget.hideTab ?? false)) && isTabInactive) || isLoading, + listEmptyWidget: widget.listEmptyWidget, + loadingNextPage: loadingNextPage, + markAsRead: _markNotificationAsRead, + notifications: data, + onCardClick: widget.onCardClick, + onEndReached: onEndReached, + onRefresh: onRefresh, + scrollController: _controller, + ); + } + @override Widget build(BuildContext context) { final colors = SirenAppTheme.colors(isDarkMode: widget.darkMode ?? false); - - return Scaffold( - backgroundColor: - widget.theme?.backgroundColor ?? colors.scaffoldBackgroundColor, - appBar: SirenAppBar( - colors: widget.theme, - isDarkMode: widget.darkMode, - onClearAllPressed: onBulkDelete, - isNonEmptyNotifications: shouldShowClearAllButton(), - headerParams: widget.headerParams, - styles: widget.customStyles, - ), - body: InboxBody( - cardParams: widget.cardParams, - colors: widget.theme, - customCard: widget.customCard, - customErrorWidget: widget.customErrorWidget, - customLoader: widget.customLoader, - customStyles: widget.customStyles, - deleteNotification: deleteNotification, - deletingNotificationId: deletingNotificationId, - disableAutoMarkAsRead: - widget.cardParams?.disableAutoMarkAsRead ?? false, - endReached: isEndReached, - isDarkMode: widget.darkMode, - isError: isError, - isLoading: isLoading, - listEmptyWidget: widget.listEmptyWidget, - loadingNextPage: loadingNextPage, - markAsRead: _markNotificationAsRead, - notifications: notifications, - onCardClick: widget.onCardClick, - onEndReached: onEndReached, - onRefresh: onRefresh, - scrollController: _scrollController, - ), - ); + final tabs = widget.tabParams?.tabs ?? Generics.inboxTabs; + + if ((widget.hideTab ?? false) == false) { + return Scaffold( + backgroundColor: + widget.theme?.backgroundColor ?? colors.scaffoldBackgroundColor, + appBar: SirenAppBar( + colors: widget.theme, + isDarkMode: widget.darkMode, + onClearAllPressed: onBulkDelete, + isNonEmptyNotifications: _enableClearAll, + headerParams: widget.headerParams, + styles: widget.customStyles, + ), + body: Column( + children: [ + Container( + margin: widget.customStyles?.tabStyles?.containerStyle?.margin ?? + EdgeInsets.zero, + color: widget.theme?.tabColors?.containerBackgroundColor ?? + Colors.transparent, + child: TabBar( + controller: _tabController, + isScrollable: true, + padding: + widget.customStyles?.tabStyles?.containerStyle?.padding ?? + const EdgeInsets.symmetric(horizontal: 24), + indicator: widget.customTabIndicator ?? + UnderlineTabIndicator( + borderSide: BorderSide( + color: widget.theme?.tabColors?.activeTabTextColor ?? + colors.tabBarActiveColor, + width: + widget.customStyles?.tabStyles?.indicatorSize ?? 4, + ), + ), + indicatorPadding: + widget.customStyles?.tabStyles?.indicatorPadding ?? + EdgeInsets.zero, + indicatorSize: TabBarIndicatorSize.tab, + tabAlignment: TabAlignment.start, + dividerColor: + widget.theme?.tabColors?.containerBackgroundColor ?? + colors.scaffoldBackgroundColor, + labelColor: widget.theme?.tabColors?.activeTabTextColor ?? + colors.tabBarActiveColor, + unselectedLabelColor: + widget.theme?.tabColors?.inactiveTabTextColor ?? + colors.tabBarInActiveColor, + labelPadding: EdgeInsets.zero, + labelStyle: + widget.customStyles?.tabStyles?.activeTabTextStyle ?? + const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + ), + unselectedLabelStyle: + widget.customStyles?.tabStyles?.inActiveTabTextStyle ?? + const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + ), + onTap: onTabChanged, + tabs: tabs.asMap().entries.map((entry) { + final index = entry.key; + final tabItem = entry.value; + return Container( + padding: const EdgeInsets.symmetric(horizontal: 20), + color: _activeTabIndex == index + ? widget.theme?.tabColors?.activeTabBackgroundColor ?? + Colors.transparent + : Colors.transparent, + child: Tab( + child: Text(tabItem.title), + ), + ); + }).toList(), + ), + ), + if (widget.customStyles?.hideTabMargin?.lower != true) + Container( + height: 1, + margin: + widget.customStyles?.tabStyles?.containerStyle?.margin ?? + EdgeInsets.zero, + color: widget.theme?.cardColors?.borderColor ?? + widget.theme?.borderColor ?? + colors.cardBorderColor, + ), + Expanded( + child: TabBarView( + controller: _tabController, + children: [ + ...List.generate( + tabs.length, + (index) => _buildInboxBody( + _tabScrollControllers[index], + index == _activeTabIndex ? notifications : [], + index != _activeTabIndex, + ), + ), + ], + ), + ), + ], + ), + ); + } else { + return Scaffold( + backgroundColor: + widget.theme?.backgroundColor ?? colors.scaffoldBackgroundColor, + appBar: SirenAppBar( + colors: widget.theme, + isDarkMode: widget.darkMode, + onClearAllPressed: onBulkDelete, + isNonEmptyNotifications: _enableClearAll, + headerParams: widget.headerParams, + styles: widget.customStyles, + ), + body: _buildInboxBody(_inboxScrollController, notifications, false), + ); + } } } diff --git a/pub_login.sh b/pub_login.sh new file mode 100644 index 0000000..8c32776 --- /dev/null +++ b/pub_login.sh @@ -0,0 +1,28 @@ +# This script creates/updates credentials.json file which is used +# to authorize publisher when publishing packages to pub.dev + +# Checking whether the secrets are available as environment +# variables or not. +if [ -z "${INPUT_ACCESS_TOKEN}" ]; then + echo "Missing INPUT_ACCESS_TOKEN environment variable" + exit 1 +fi + +if [ -z "${INPUT_REFRESH_TOKEN}" ]; then + echo "Missing INPUT_REFRESH_TOKEN environment variable" + exit 1 +fi + +# Create credentials.json file. + echo "Copy credentials" + + mkdir -p ~/.config/dart + cat <<-EOF > ~/.config/dart/pub-credentials.json + { + "accessToken":"$INPUT_ACCESS_TOKEN", + "refreshToken":"$INPUT_REFRESH_TOKEN", + "tokenEndpoint":"https://accounts.google.com/o/oauth2/token", + "scopes": [ "openid", "https://www.googleapis.com/auth/userinfo.email" ], + "expiration": 1577149838000 + } +EOF \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..5e06fd1 --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,581 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" + url: "https://pub.dev" + source: hosted + version: "67.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" + url: "https://pub.dev" + source: hosted + version: "6.4.1" + args: + dependency: transitive + description: + name: args + sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" + url: "https://pub.dev" + source: hosted + version: "2.5.0" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + build: + dependency: transitive + description: + name: build + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + build_config: + dependency: transitive + description: + name: build_config + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + url: "https://pub.dev" + source: hosted + version: "1.1.1" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" + url: "https://pub.dev" + source: hosted + version: "4.0.1" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22" + url: "https://pub.dev" + source: hosted + version: "2.4.9" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: "4ae8ffe5ac758da294ecf1802f2aff01558d8b1b00616aa7538ea9a8a5d50799" + url: "https://pub.dev" + source: hosted + version: "7.3.0" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb + url: "https://pub.dev" + source: hosted + version: "8.9.2" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 + url: "https://pub.dev" + source: hosted + version: "4.10.0" + collection: + dependency: transitive + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" + url: "https://pub.dev" + source: hosted + version: "2.3.6" + dio: + dependency: "direct main" + description: + name: dio + sha256: "49af28382aefc53562459104f64d16b9dfd1e8ef68c862d5af436cc8356ce5a8" + url: "https://pub.dev" + source: hosted + version: "5.4.1" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + file: + dependency: transitive + description: + name: file + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 + url: "https://pub.dev" + source: hosted + version: "2.0.3" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" + source: hosted + version: "4.0.0" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + graphs: + dependency: transitive + description: + name: graphs + sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + url: "https://pub.dev" + source: hosted + version: "2.3.1" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + husky: + dependency: "direct dev" + description: + name: husky + sha256: ce4a92b311c03e67ff66b6e354c8d5b8ee7c663ccaedb954e93798658b439bb2 + url: "https://pub.dev" + source: hosted + version: "0.1.7" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + js: + dependency: transitive + description: + name: js + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf + url: "https://pub.dev" + source: hosted + version: "0.7.1" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + url: "https://pub.dev" + source: hosted + version: "10.0.0" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + lints: + dependency: transitive + description: + name: lints + sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" + source: hosted + version: "0.12.16+1" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + url: "https://pub.dev" + source: hosted + version: "0.8.0" + meta: + dependency: transitive + description: + name: meta + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + url: "https://pub.dev" + source: hosted + version: "1.11.0" + mime: + dependency: transitive + description: + name: mime + sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" + url: "https://pub.dev" + source: hosted + version: "1.0.5" + mockito: + dependency: "direct dev" + description: + name: mockito + sha256: "6841eed20a7befac0ce07df8116c8b8233ed1f4486a7647c7fc5a02ae6163917" + url: "https://pub.dev" + source: hosted + version: "5.4.4" + network_image_mock: + dependency: "direct dev" + description: + name: network_image_mock + sha256: "855cdd01d42440e0cffee0d6c2370909fc31b3bcba308a59829f24f64be42db7" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path: + dependency: transitive + description: + name: path + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 + url: "https://pub.dev" + source: hosted + version: "1.2.3" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + url: "https://pub.dev" + source: hosted + version: "0.6.1" + timing: + dependency: transitive + description: + name: timing + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + very_good_analysis: + dependency: "direct dev" + description: + name: very_good_analysis + sha256: cecd7a0e92978dbece97c255502c8965f2db3439cde5a11f4b2c65f1955911ee + url: "https://pub.dev" + source: hosted + version: "2.4.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + url: "https://pub.dev" + source: hosted + version: "13.0.0" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" + url: "https://pub.dev" + source: hosted + version: "0.5.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42" + url: "https://pub.dev" + source: hosted + version: "2.4.5" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" +sdks: + dart: ">=3.3.0 <4.0.0" + flutter: ">=3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 82252c8..28b9aa2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ environment: dependencies: flutter: sdk: flutter - dio: '>=5.2.0 <=5.4.3' + dio: '>=5.2.0 <=5.4.3+1' dev_dependencies: flutter_test: @@ -32,9 +32,15 @@ dev_dependencies: # following page: https://dart.dev/tools/pub/pubspec flutter: - assets: - env +topics: + - flutter + - siren + - in-app + - notifications + + diff --git a/test/constants/generics_test.dart b/test/constants/generics_test.dart index 49956b1..dc0dce0 100644 --- a/test/constants/generics_test.dart +++ b/test/constants/generics_test.dart @@ -1,5 +1,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:sirenapp_flutter_inbox/src/constants/generics.dart'; +import 'package:sirenapp_flutter_inbox/src/constants/strings.dart'; import 'package:sirenapp_flutter_inbox/src/errors/errors.dart'; void main() { @@ -17,6 +18,16 @@ void main() { Errors.defaultError.message, 'Something went wrong', ); + + expect(Generics.inboxTabs.length, 2); + expect(Generics.inboxTabs[0].key, 'ALL'); + expect(Generics.inboxTabs[0].title, Strings.tabAll); + expect(Generics.inboxTabs[1].key, 'UNREAD'); + expect(Generics.inboxTabs[1].title, Strings.tabUnread); + + expect(Generics.emptyMessages.length, 2); + expect(Generics.emptyMessages[0], Strings.empty_title); + expect(Generics.emptyMessages[1], Strings.empty_title_unread); }); }); diff --git a/test/data/siren_data_provider_test.mocks.dart b/test/data/siren_data_provider_test.mocks.dart index 54dc9b7..f4a1d01 100644 --- a/test/data/siren_data_provider_test.mocks.dart +++ b/test/data/siren_data_provider_test.mocks.dart @@ -1,4 +1,4 @@ -// Mocks generated by Mockito 5.3.2 from annotations +// Mocks generated by Mockito 5.4.4 from annotations // in sirenapp_flutter_inbox/test/data/siren_data_provider_test.dart. // Do not manually edit this file. @@ -15,6 +15,8 @@ import 'package:sirenapp_flutter_inbox/src/services/api_client.dart' as _i2; // ignore_for_file: avoid_redundant_argument_values // ignore_for_file: avoid_setters_without_getters // ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member // ignore_for_file: prefer_const_constructors @@ -58,6 +60,7 @@ class MockVerifyToken extends _i1.Mock implements _i4.VerifyToken { Invocation.getter(#api), ), ) as _i2.ApiClient); + @override set api(_i2.ApiClient? _api) => super.noSuchMethod( Invocation.setter( @@ -66,6 +69,7 @@ class MockVerifyToken extends _i1.Mock implements _i4.VerifyToken { ), returnValueForMissingStub: null, ); + @override _i5.Status convertJsonToVerificationStatus(dynamic response) => (super.noSuchMethod( @@ -76,6 +80,7 @@ class MockVerifyToken extends _i1.Mock implements _i4.VerifyToken { returnValue: _i5.Status.PENDING, returnValueForMissingStub: _i5.Status.PENDING, ) as _i5.Status); + @override _i6.Future<_i3.ApiResponse> verifyToken() => (super.noSuchMethod( Invocation.method( diff --git a/test/models/notification_model_test.dart b/test/models/notification_model_test.dart index 8fcf33a..84dc69b 100644 --- a/test/models/notification_model_test.dart +++ b/test/models/notification_model_test.dart @@ -15,13 +15,15 @@ void main() { 'body': 'body', 'actionUrl': 'actionUrl', 'avatar': {'imageUrl': 'avatarUrl', 'altText': 'altText'}, - 'additionalData': 'additionalData', + 'additionalData': {}, }, 'requestId': 'requestId', 'isRead': true, 'cardColor': Colors.blue, }; - final notification = NotificationType.fromJson(json); + + final notification = + NotificationType.fromJson(Map.from(json)); expect(notification.id, 'notificationId'); expect(notification.createdAt, '2022-01-01T00:00:00Z'); @@ -35,7 +37,7 @@ void main() { expect(notification.message.actionUrl, 'actionUrl'); expect(notification.message.avatar?.url, 'avatarUrl'); expect(notification.message.avatar?.altText, 'altText'); - expect(notification.message.additionalData, 'additionalData'); + expect(notification.message.additionalData, {}); }); test('markAsRead() should mark the notification as read', () { @@ -49,7 +51,7 @@ void main() { body: 'body', actionUrl: 'actionUrl', avatar: AvatarData(url: 'avatarUrl', altText: 'altText'), - additionalData: 'additionalData', + additionalData: {}, ), requestId: 'requestId', isRead: false, @@ -75,9 +77,10 @@ void main() { 'body': 'body', 'actionUrl': 'actionUrl', 'avatar': {'imageUrl': 'avatarUrl', 'altText': 'altText'}, - 'additionalData': 'additionalData', + 'additionalData': {}, }; - final message = MessageData.fromJson(json); + + final message = MessageData.fromJson(Map.from(json)); expect(message.channel, 'channel'); expect(message.header, 'header'); @@ -86,14 +89,15 @@ void main() { expect(message.actionUrl, 'actionUrl'); expect(message.avatar?.url, 'avatarUrl'); expect(message.avatar?.altText, 'altText'); - expect(message.additionalData, 'additionalData'); + expect(message.additionalData, {}); }); }); group('AvatarData', () { test('fromJson() should parse JSON correctly', () { final json = {'imageUrl': 'avatarUrl', 'altText': 'altText'}; - final avatar = AvatarData.fromJson(json); + + final avatar = AvatarData.fromJson(Map.from(json)); expect(avatar.url, 'avatarUrl'); expect(avatar.altText, 'altText'); diff --git a/test/models/ui_models_test.dart b/test/models/ui_models_test.dart index a441546..7ab5d81 100644 --- a/test/models/ui_models_test.dart +++ b/test/models/ui_models_test.dart @@ -112,4 +112,81 @@ void main() { expect(cardParams.hideAvatar, hideAvatar); expect(cardParams.deleteIcon, deleteWidget); }); + + group('TimerIconStyle', () { + test('constructor should initialize size property with provided value', () { + final timerIconStyle = TimerIconStyle(size: 24); + expect(timerIconStyle.size, 24.0); + }); + }); + + group('DeleteIconStyle', () { + test('constructor should initialize size property with provided value', () { + final deleteIconStyle = DeleteIconStyle(size: 24); + expect(deleteIconStyle.size, 24.0); + }); + }); + + group('ClearAllIconStyle', () { + test('constructor should initialize size property with provided value', () { + final clearAllIconStyle = ClearAllIconStyle(size: 24); + expect(clearAllIconStyle.size, 24.0); + }); + }); + + group('InboxHeaderColors', () { + test('constructor should initialize properties with provided values', () { + final inboxHeaderColors = InboxHeaderColors( + background: Colors.white, + titleColor: Colors.black, + ); + expect(inboxHeaderColors.background, Colors.white); + expect(inboxHeaderColors.titleColor, Colors.black); + }); + }); + + group('BadgeColors', () { + test('constructor should initialize properties with provided values', () { + final badgeColors = BadgeColors( + backgroundColor: Colors.red, + color: Colors.white, + ); + expect(badgeColors.backgroundColor, Colors.red); + expect(badgeColors.color, Colors.white); + }); + }); + + group('InboxHeaderStyle', () { + test('constructor should initialize properties with provided values', () { + final inboxHeaderStyle = InboxHeaderStyle(borderWidth: 5); + expect(inboxHeaderStyle.borderWidth, 5); + // expect(inboxHeaderStyle.textColor, Colors.black); + }); + }); + + group('TabParams', () { + test('constructor should initialize properties with provided values', () { + final tabParams = TabParams(activeTabIndex: 2); + expect(tabParams.activeTabIndex, 2); + // expect(tabParams.tabIcon, Icon(Icons.home)); + }); + }); + + group('TabStyles', () { + test('constructor should initialize properties with provided values', () { + final tabStyles = TabStyles(indicatorSize: 2); + expect(tabStyles.indicatorSize, 2); + }); + }); + + group('TabColors', () { + test('constructor should initialize properties with provided values', () { + final tabColors = TabColors( + containerBackgroundColor: Colors.white, + inactiveTabTextColor: Colors.black, + ); + expect(tabColors.containerBackgroundColor, Colors.white); + expect(tabColors.inactiveTabTextColor, Colors.black); + }); + }); } diff --git a/test/services/api_client_test.mocks.dart b/test/services/api_client_test.mocks.dart index 888d18f..b2d0ecc 100644 --- a/test/services/api_client_test.mocks.dart +++ b/test/services/api_client_test.mocks.dart @@ -1,4 +1,4 @@ -// Mocks generated by Mockito 5.3.2 from annotations +// Mocks generated by Mockito 5.4.4 from annotations // in sirenapp_flutter_inbox/test/services/api_client_test.dart. // Do not manually edit this file. @@ -13,8 +13,9 @@ import 'package:dio/src/options.dart' as _i2; import 'package:dio/src/response.dart' as _i6; import 'package:dio/src/transformer.dart' as _i4; import 'package:mockito/mockito.dart' as _i1; +import 'package:mockito/src/dummies.dart' as _i12; import 'package:sirenapp_flutter_inbox/sirenapp_flutter_inbox.dart' as _i8; -import 'package:sirenapp_flutter_inbox/src/constants/generics.dart' as _i12; +import 'package:sirenapp_flutter_inbox/src/constants/generics.dart' as _i13; import 'package:sirenapp_flutter_inbox/src/data/siren_data_provider.dart' as _i11; @@ -22,6 +23,8 @@ import 'package:sirenapp_flutter_inbox/src/data/siren_data_provider.dart' // ignore_for_file: avoid_redundant_argument_values // ignore_for_file: avoid_setters_without_getters // ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member // ignore_for_file: prefer_const_constructors @@ -70,7 +73,7 @@ class _FakeInterceptors_3 extends _i1.SmartFake implements _i5.Interceptors { ); } -class _FakeResponse_4 extends _i1.SmartFake implements _i6.Response { +class _FakeResponse_4 extends _i1.SmartFake implements _i6.Response { _FakeResponse_4( Object parent, Invocation parentInvocation, @@ -118,6 +121,7 @@ class MockDio extends _i1.Mock implements _i9.Dio { Invocation.getter(#options), ), ) as _i2.BaseOptions); + @override set options(_i2.BaseOptions? _options) => super.noSuchMethod( Invocation.setter( @@ -126,6 +130,7 @@ class MockDio extends _i1.Mock implements _i9.Dio { ), returnValueForMissingStub: null, ); + @override _i3.HttpClientAdapter get httpClientAdapter => (super.noSuchMethod( Invocation.getter(#httpClientAdapter), @@ -138,6 +143,7 @@ class MockDio extends _i1.Mock implements _i9.Dio { Invocation.getter(#httpClientAdapter), ), ) as _i3.HttpClientAdapter); + @override set httpClientAdapter(_i3.HttpClientAdapter? _httpClientAdapter) => super.noSuchMethod( @@ -147,6 +153,7 @@ class MockDio extends _i1.Mock implements _i9.Dio { ), returnValueForMissingStub: null, ); + @override _i4.Transformer get transformer => (super.noSuchMethod( Invocation.getter(#transformer), @@ -159,6 +166,7 @@ class MockDio extends _i1.Mock implements _i9.Dio { Invocation.getter(#transformer), ), ) as _i4.Transformer); + @override set transformer(_i4.Transformer? _transformer) => super.noSuchMethod( Invocation.setter( @@ -167,6 +175,7 @@ class MockDio extends _i1.Mock implements _i9.Dio { ), returnValueForMissingStub: null, ); + @override _i5.Interceptors get interceptors => (super.noSuchMethod( Invocation.getter(#interceptors), @@ -179,6 +188,7 @@ class MockDio extends _i1.Mock implements _i9.Dio { Invocation.getter(#interceptors), ), ) as _i5.Interceptors); + @override void close({bool? force = false}) => super.noSuchMethod( Invocation.method( @@ -188,6 +198,7 @@ class MockDio extends _i1.Mock implements _i9.Dio { ), returnValueForMissingStub: null, ); + @override _i7.Future<_i6.Response> head( String? path, { @@ -235,6 +246,7 @@ class MockDio extends _i1.Mock implements _i9.Dio { ), )), ) as _i7.Future<_i6.Response>); + @override _i7.Future<_i6.Response> headUri( Uri? uri, { @@ -278,6 +290,7 @@ class MockDio extends _i1.Mock implements _i9.Dio { ), )), ) as _i7.Future<_i6.Response>); + @override _i7.Future<_i6.Response> get( String? path, { @@ -329,6 +342,7 @@ class MockDio extends _i1.Mock implements _i9.Dio { ), )), ) as _i7.Future<_i6.Response>); + @override _i7.Future<_i6.Response> getUri( Uri? uri, { @@ -376,6 +390,7 @@ class MockDio extends _i1.Mock implements _i9.Dio { ), )), ) as _i7.Future<_i6.Response>); + @override _i7.Future<_i6.Response> post( String? path, { @@ -431,6 +446,7 @@ class MockDio extends _i1.Mock implements _i9.Dio { ), )), ) as _i7.Future<_i6.Response>); + @override _i7.Future<_i6.Response> postUri( Uri? uri, { @@ -482,6 +498,7 @@ class MockDio extends _i1.Mock implements _i9.Dio { ), )), ) as _i7.Future<_i6.Response>); + @override _i7.Future<_i6.Response> put( String? path, { @@ -537,6 +554,7 @@ class MockDio extends _i1.Mock implements _i9.Dio { ), )), ) as _i7.Future<_i6.Response>); + @override _i7.Future<_i6.Response> putUri( Uri? uri, { @@ -588,6 +606,7 @@ class MockDio extends _i1.Mock implements _i9.Dio { ), )), ) as _i7.Future<_i6.Response>); + @override _i7.Future<_i6.Response> patch( String? path, { @@ -643,6 +662,7 @@ class MockDio extends _i1.Mock implements _i9.Dio { ), )), ) as _i7.Future<_i6.Response>); + @override _i7.Future<_i6.Response> patchUri( Uri? uri, { @@ -694,6 +714,7 @@ class MockDio extends _i1.Mock implements _i9.Dio { ), )), ) as _i7.Future<_i6.Response>); + @override _i7.Future<_i6.Response> delete( String? path, { @@ -741,6 +762,7 @@ class MockDio extends _i1.Mock implements _i9.Dio { ), )), ) as _i7.Future<_i6.Response>); + @override _i7.Future<_i6.Response> deleteUri( Uri? uri, { @@ -784,6 +806,7 @@ class MockDio extends _i1.Mock implements _i9.Dio { ), )), ) as _i7.Future<_i6.Response>); + @override _i7.Future<_i6.Response> download( String? urlPath, @@ -854,6 +877,7 @@ class MockDio extends _i1.Mock implements _i9.Dio { ), )), ) as _i7.Future<_i6.Response>); + @override _i7.Future<_i6.Response> downloadUri( Uri? uri, @@ -920,6 +944,7 @@ class MockDio extends _i1.Mock implements _i9.Dio { ), )), ) as _i7.Future<_i6.Response>); + @override _i7.Future<_i6.Response> request( String? url, { @@ -975,6 +1000,7 @@ class MockDio extends _i1.Mock implements _i9.Dio { ), )), ) as _i7.Future<_i6.Response>); + @override _i7.Future<_i6.Response> requestUri( Uri? uri, { @@ -1026,6 +1052,7 @@ class MockDio extends _i1.Mock implements _i9.Dio { ), )), ) as _i7.Future<_i6.Response>); + @override _i7.Future<_i6.Response> fetch(_i2.RequestOptions? requestOptions) => (super.noSuchMethod( @@ -1058,9 +1085,16 @@ class MockSirenDataProvider extends _i1.Mock implements _i11.SirenDataProvider { @override String get userToken => (super.noSuchMethod( Invocation.getter(#userToken), - returnValue: '', - returnValueForMissingStub: '', + returnValue: _i12.dummyValue( + this, + Invocation.getter(#userToken), + ), + returnValueForMissingStub: _i12.dummyValue( + this, + Invocation.getter(#userToken), + ), ) as String); + @override set userToken(String? _userToken) => super.noSuchMethod( Invocation.setter( @@ -1069,12 +1103,20 @@ class MockSirenDataProvider extends _i1.Mock implements _i11.SirenDataProvider { ), returnValueForMissingStub: null, ); + @override String get recipientId => (super.noSuchMethod( Invocation.getter(#recipientId), - returnValue: '', - returnValueForMissingStub: '', + returnValue: _i12.dummyValue( + this, + Invocation.getter(#recipientId), + ), + returnValueForMissingStub: _i12.dummyValue( + this, + Invocation.getter(#recipientId), + ), ) as String); + @override set recipientId(String? _recipientId) => super.noSuchMethod( Invocation.setter( @@ -1083,12 +1125,20 @@ class MockSirenDataProvider extends _i1.Mock implements _i11.SirenDataProvider { ), returnValueForMissingStub: null, ); + @override String get apiDomain => (super.noSuchMethod( Invocation.getter(#apiDomain), - returnValue: '', - returnValueForMissingStub: '', + returnValue: _i12.dummyValue( + this, + Invocation.getter(#apiDomain), + ), + returnValueForMissingStub: _i12.dummyValue( + this, + Invocation.getter(#apiDomain), + ), ) as String); + @override set apiDomain(String? _apiDomain) => super.noSuchMethod( Invocation.setter( @@ -1097,6 +1147,7 @@ class MockSirenDataProvider extends _i1.Mock implements _i11.SirenDataProvider { ), returnValueForMissingStub: null, ); + @override _i7.StreamController<_i8.StreamResponse> get inboxController => (super.noSuchMethod( @@ -1110,6 +1161,7 @@ class MockSirenDataProvider extends _i1.Mock implements _i11.SirenDataProvider { Invocation.getter(#inboxController), ), ) as _i7.StreamController<_i8.StreamResponse>); + @override _i7.StreamController<_i8.StreamResponse> get iconController => (super.noSuchMethod( @@ -1123,18 +1175,21 @@ class MockSirenDataProvider extends _i1.Mock implements _i11.SirenDataProvider { Invocation.getter(#iconController), ), ) as _i7.StreamController<_i8.StreamResponse>); + @override - _i12.Status get tokenVerificationStatus => (super.noSuchMethod( + _i13.Status get tokenVerificationStatus => (super.noSuchMethod( Invocation.getter(#tokenVerificationStatus), - returnValue: _i12.Status.PENDING, - returnValueForMissingStub: _i12.Status.PENDING, - ) as _i12.Status); + returnValue: _i13.Status.PENDING, + returnValueForMissingStub: _i13.Status.PENDING, + ) as _i13.Status); + @override bool get isProviderInitialized => (super.noSuchMethod( Invocation.getter(#isProviderInitialized), returnValue: false, returnValueForMissingStub: false, ) as bool); + @override _i7.Future initialize() => (super.noSuchMethod( Invocation.method( @@ -1144,6 +1199,7 @@ class MockSirenDataProvider extends _i1.Mock implements _i11.SirenDataProvider { returnValue: _i7.Future.value(), returnValueForMissingStub: _i7.Future.value(), ) as _i7.Future); + @override void updateParams({ required String? userToken, @@ -1160,14 +1216,16 @@ class MockSirenDataProvider extends _i1.Mock implements _i11.SirenDataProvider { ), returnValueForMissingStub: null, ); + @override - void triggerError() => super.noSuchMethod( + void triggerEvent(_i13.UpdateEvents? event) => super.noSuchMethod( Invocation.method( - #triggerError, - [], + #triggerEvent, + [event], ), returnValueForMissingStub: null, ); + @override _i8.SirenErrorType getVerificationErrorType() => (super.noSuchMethod( Invocation.method( @@ -1189,6 +1247,7 @@ class MockSirenDataProvider extends _i1.Mock implements _i11.SirenDataProvider { ), ), ) as _i8.SirenErrorType); + @override void iconDispose() => super.noSuchMethod( Invocation.method( @@ -1197,6 +1256,7 @@ class MockSirenDataProvider extends _i1.Mock implements _i11.SirenDataProvider { ), returnValueForMissingStub: null, ); + @override void inboxDispose() => super.noSuchMethod( Invocation.method( diff --git a/test/services/network_service_test.mocks.dart b/test/services/network_service_test.mocks.dart index 9c0af93..ee1e372 100644 --- a/test/services/network_service_test.mocks.dart +++ b/test/services/network_service_test.mocks.dart @@ -1,4 +1,4 @@ -// Mocks generated by Mockito 5.3.2 from annotations +// Mocks generated by Mockito 5.4.4 from annotations // in sirenapp_flutter_inbox/test/services/network_service_test.dart. // Do not manually edit this file. @@ -14,6 +14,8 @@ import 'package:sirenapp_flutter_inbox/src/services/api_client.dart' as _i3; // ignore_for_file: avoid_redundant_argument_values // ignore_for_file: avoid_setters_without_getters // ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member // ignore_for_file: prefer_const_constructors @@ -44,6 +46,7 @@ class MockApiClient extends _i1.Mock implements _i3.ApiClient { returnValue: false, returnValueForMissingStub: false, ) as bool); + @override _i5.Future<_i2.DioResponse> get({ String? path, @@ -94,6 +97,7 @@ class MockApiClient extends _i1.Mock implements _i3.ApiClient { ), )), ) as _i5.Future<_i2.DioResponse>); + @override _i5.Future<_i2.DioResponse> post({ String? path, @@ -152,6 +156,7 @@ class MockApiClient extends _i1.Mock implements _i3.ApiClient { ), )), ) as _i5.Future<_i2.DioResponse>); + @override _i5.Future<_i2.DioResponse> patch({ String? path, @@ -210,6 +215,7 @@ class MockApiClient extends _i1.Mock implements _i3.ApiClient { ), )), ) as _i5.Future<_i2.DioResponse>); + @override _i5.Future<_i2.DioResponse> delete({ String? path, diff --git a/test/utils/siren_test.dart b/test/utils/siren_test.dart index 204ef2f..07cb8aa 100644 --- a/test/utils/siren_test.dart +++ b/test/utils/siren_test.dart @@ -1,75 +1,71 @@ -// ignore_for_file: cascade_invocations - import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; -import 'package:sirenapp_flutter_inbox/sirenapp_flutter_inbox.dart'; -import 'package:sirenapp_flutter_inbox/src/api/notifications_bulk_update.dart'; -import 'package:sirenapp_flutter_inbox/src/api/read_notification_by_id.dart'; -import 'package:sirenapp_flutter_inbox/src/constants/generics.dart'; -import 'package:sirenapp_flutter_inbox/src/data/siren_data_provider.dart'; +import 'package:sirenapp_flutter_inbox/src/utils/siren.dart'; -class MockReadNotificationById extends Mock implements ReadNotificationById { - @override - Future readNotificationById({ - required String notificationId, - }) { - final result = ApiResponse()..data = 'SUCCESS'; - result.error = null; - return Future(() => result); - } -} +void main() { + group('Siren', () { + test('markAsReadById should mark a notification as read', () async { + // Arrange + const id = 'notification_id'; -class MockNotificationsBulkUpdate extends Mock - implements NotificationsBulkUpdate { - @override - Future notificationsBulkUpdate({ - required Map data, - required String operation, - }) { - final result = ApiResponse()..data = 'SUCCESS'; - result.error = null; - return Future(() => result); - } -} + // Act + final result = await Siren.markAsReadById(id: id); -class MockSirenDataProvider extends Mock implements SirenDataProvider {} + // Assert + expect(result, isNotNull); + // Add more assertions here + }); -void main() { - late MockReadNotificationById mockReadNotificationById; - late MockNotificationsBulkUpdate mockMockNotificationsBulkUpdate; + test( + 'markAsReadByDate should mark notifications as read until a specific date', + () async { + // Arrange + const startDate = '2022-01-01T00:00:00Z'; - setUp(() { - mockReadNotificationById = MockReadNotificationById(); - mockMockNotificationsBulkUpdate = MockNotificationsBulkUpdate(); - }); + // Act + final result = await Siren.markAsReadByDate(startDate: startDate); - test( - 'markAsRead method should call ReadNotificationById and update inboxController', - () async { - const notificationId = 'notification_id'; - final mockResponse = ApiResponse(data: 'SUCCESS'); - final response = await mockReadNotificationById.readNotificationById( - notificationId: notificationId, - ); + // Assert + expect(result, isNotNull); + // Add more assertions here + }); - expect(mockResponse.data, response.data); - }); + test( + 'markAllAsViewed should mark all notifications as viewed until a specific date', + () async { + // Arrange + const startDate = '2022-01-01T00:00:00Z'; + + // Act + final result = await Siren.markAllAsViewed(startDate: startDate); + + // Assert + expect(result, isNotNull); + // Add more assertions here + }); + + test('deleteById should delete a notification by its ID', () async { + // Arrange + const id = 'notification_id'; + + // Act + final result = await Siren.deleteById(id: id); + + // Assert + expect(result, isNotNull); + // Add more assertions here + }); + + test('deleteByDate should delete notifications until a specific date', + () async { + // Arrange + const startDate = '2022-01-01T00:00:00Z'; - test( - 'mark notifications as read by a specific date and update inboxController', - () async { - const startDate = '2024-03-15T04:07:14.577928Z'; - final mockData = { - 'until': startDate, - 'operation': BulkUpdateType.MARK_AS_READ.name, - }; - final mockResponse = ApiResponse(data: 'SUCCESS'); - final response = - await mockMockNotificationsBulkUpdate.notificationsBulkUpdate( - data: mockData, - operation: BulkUpdateType.MARK_AS_READ.name, - ); + // Act + final result = await Siren.deleteByDate(startDate: startDate); - expect(mockResponse.data, response.data); + // Assert + expect(result, isNotNull); + // Add more assertions here + }); }); } diff --git a/test/widgets/card_test.dart b/test/widgets/card_test.dart index b5c4ee1..9c646dd 100644 --- a/test/widgets/card_test.dart +++ b/test/widgets/card_test.dart @@ -29,7 +29,7 @@ void main() { altText: 'Test alt text', url: 'https://picsum.photos/200/300', ), - additionalData: 'Test Additional Data', + additionalData: {}, ), requestId: '456', isRead: false, diff --git a/test/widgets/empty_widget_test.dart b/test/widgets/empty_widget_test.dart index db239f7..a354913 100644 --- a/test/widgets/empty_widget_test.dart +++ b/test/widgets/empty_widget_test.dart @@ -11,7 +11,9 @@ void main() { MaterialApp( home: Builder( builder: (context) { - return const EmptyWidget(); + return const EmptyWidget( + activeTabIndex: 0, + ); }, ), ), @@ -35,7 +37,9 @@ void main() { final theme = Theme.of(context); return MaterialApp( theme: theme.copyWith(), - home: const EmptyWidget(), + home: const EmptyWidget( + activeTabIndex: 0, + ), ); }, ), diff --git a/test/widgets/inbox_body_test.dart b/test/widgets/inbox_body_test.dart index c2a008e..1a0040a 100644 --- a/test/widgets/inbox_body_test.dart +++ b/test/widgets/inbox_body_test.dart @@ -27,6 +27,7 @@ void main() { endReached: false, onEndReached: () {}, scrollController: ScrollController(), + activeTabIndex: 0, ), ), ); @@ -53,6 +54,7 @@ void main() { endReached: false, onEndReached: () {}, scrollController: ScrollController(), + activeTabIndex: 0, ), ), ); @@ -75,7 +77,7 @@ void main() { altText: 'Test alt text', url: 'https://picsum.photos/200/300', ), - additionalData: 'Test Additional Data', + additionalData: {}, ), requestId: 'request-id', isRead: false, @@ -100,6 +102,7 @@ void main() { endReached: false, onEndReached: () {}, scrollController: ScrollController(), + activeTabIndex: 0, ), ), ); diff --git a/test/widgets/notification_list_view_test.dart b/test/widgets/notification_list_view_test.dart index c23d396..b12012d 100644 --- a/test/widgets/notification_list_view_test.dart +++ b/test/widgets/notification_list_view_test.dart @@ -24,7 +24,7 @@ void main() { altText: 'Test alt text', url: 'https://picsum.photos/200/300', ), - additionalData: 'Test Additional Data', + additionalData: {}, ), requestId: 'request-id', isRead: false, diff --git a/test/widgets/siren_inbox_icon_test.mocks.dart b/test/widgets/siren_inbox_icon_test.mocks.dart index 507e251..cc7c558 100644 --- a/test/widgets/siren_inbox_icon_test.mocks.dart +++ b/test/widgets/siren_inbox_icon_test.mocks.dart @@ -1,4 +1,4 @@ -// Mocks generated by Mockito 5.3.2 from annotations +// Mocks generated by Mockito 5.4.4 from annotations // in sirenapp_flutter_inbox/test/widgets/siren_inbox_icon_test.dart. // Do not manually edit this file. @@ -6,10 +6,11 @@ import 'dart:async' as _i2; import 'package:mockito/mockito.dart' as _i1; +import 'package:mockito/src/dummies.dart' as _i6; import 'package:sirenapp_flutter_inbox/sirenapp_flutter_inbox.dart' as _i3; import 'package:sirenapp_flutter_inbox/src/api/fetch_unviewed_notification_count.dart' - as _i7; -import 'package:sirenapp_flutter_inbox/src/constants/generics.dart' as _i6; + as _i8; +import 'package:sirenapp_flutter_inbox/src/constants/generics.dart' as _i7; import 'package:sirenapp_flutter_inbox/src/data/siren_data_provider.dart' as _i5; import 'package:sirenapp_flutter_inbox/src/services/api_client.dart' as _i4; @@ -18,6 +19,8 @@ import 'package:sirenapp_flutter_inbox/src/services/api_client.dart' as _i4; // ignore_for_file: avoid_redundant_argument_values // ignore_for_file: avoid_setters_without_getters // ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member // ignore_for_file: prefer_const_constructors @@ -78,8 +81,12 @@ class MockSirenDataProvider extends _i1.Mock implements _i5.SirenDataProvider { @override String get userToken => (super.noSuchMethod( Invocation.getter(#userToken), - returnValue: '', + returnValue: _i6.dummyValue( + this, + Invocation.getter(#userToken), + ), ) as String); + @override set userToken(String? _userToken) => super.noSuchMethod( Invocation.setter( @@ -88,11 +95,16 @@ class MockSirenDataProvider extends _i1.Mock implements _i5.SirenDataProvider { ), returnValueForMissingStub: null, ); + @override String get recipientId => (super.noSuchMethod( Invocation.getter(#recipientId), - returnValue: '', + returnValue: _i6.dummyValue( + this, + Invocation.getter(#recipientId), + ), ) as String); + @override set recipientId(String? _recipientId) => super.noSuchMethod( Invocation.setter( @@ -101,11 +113,16 @@ class MockSirenDataProvider extends _i1.Mock implements _i5.SirenDataProvider { ), returnValueForMissingStub: null, ); + @override String get apiDomain => (super.noSuchMethod( Invocation.getter(#apiDomain), - returnValue: '', + returnValue: _i6.dummyValue( + this, + Invocation.getter(#apiDomain), + ), ) as String); + @override set apiDomain(String? _apiDomain) => super.noSuchMethod( Invocation.setter( @@ -114,6 +131,7 @@ class MockSirenDataProvider extends _i1.Mock implements _i5.SirenDataProvider { ), returnValueForMissingStub: null, ); + @override _i2.StreamController<_i3.StreamResponse> get inboxController => (super.noSuchMethod( @@ -123,6 +141,7 @@ class MockSirenDataProvider extends _i1.Mock implements _i5.SirenDataProvider { Invocation.getter(#inboxController), ), ) as _i2.StreamController<_i3.StreamResponse>); + @override _i2.StreamController<_i3.StreamResponse> get iconController => (super.noSuchMethod( @@ -132,16 +151,19 @@ class MockSirenDataProvider extends _i1.Mock implements _i5.SirenDataProvider { Invocation.getter(#iconController), ), ) as _i2.StreamController<_i3.StreamResponse>); + @override - _i6.Status get tokenVerificationStatus => (super.noSuchMethod( + _i7.Status get tokenVerificationStatus => (super.noSuchMethod( Invocation.getter(#tokenVerificationStatus), - returnValue: _i6.Status.PENDING, - ) as _i6.Status); + returnValue: _i7.Status.PENDING, + ) as _i7.Status); + @override bool get isProviderInitialized => (super.noSuchMethod( Invocation.getter(#isProviderInitialized), returnValue: false, ) as bool); + @override _i2.Future initialize() => (super.noSuchMethod( Invocation.method( @@ -151,6 +173,7 @@ class MockSirenDataProvider extends _i1.Mock implements _i5.SirenDataProvider { returnValue: _i2.Future.value(), returnValueForMissingStub: _i2.Future.value(), ) as _i2.Future); + @override void updateParams({ required String? userToken, @@ -167,14 +190,16 @@ class MockSirenDataProvider extends _i1.Mock implements _i5.SirenDataProvider { ), returnValueForMissingStub: null, ); + @override - void triggerError() => super.noSuchMethod( + void triggerEvent(_i7.UpdateEvents? event) => super.noSuchMethod( Invocation.method( - #triggerError, - [], + #triggerEvent, + [event], ), returnValueForMissingStub: null, ); + @override _i3.SirenErrorType getVerificationErrorType() => (super.noSuchMethod( Invocation.method( @@ -189,6 +214,7 @@ class MockSirenDataProvider extends _i1.Mock implements _i5.SirenDataProvider { ), ), ) as _i3.SirenErrorType); + @override void iconDispose() => super.noSuchMethod( Invocation.method( @@ -197,6 +223,7 @@ class MockSirenDataProvider extends _i1.Mock implements _i5.SirenDataProvider { ), returnValueForMissingStub: null, ); + @override void inboxDispose() => super.noSuchMethod( Invocation.method( @@ -211,7 +238,7 @@ class MockSirenDataProvider extends _i1.Mock implements _i5.SirenDataProvider { /// /// See the documentation for Mockito's code generation for more information. class MockFetchUnViewedNotificationsCount extends _i1.Mock - implements _i7.FetchUnViewedNotificationsCount { + implements _i8.FetchUnViewedNotificationsCount { MockFetchUnViewedNotificationsCount() { _i1.throwOnMissingStub(this); } @@ -224,6 +251,7 @@ class MockFetchUnViewedNotificationsCount extends _i1.Mock Invocation.getter(#api), ), ) as _i4.ApiClient); + @override set api(_i4.ApiClient? _api) => super.noSuchMethod( Invocation.setter( @@ -232,6 +260,7 @@ class MockFetchUnViewedNotificationsCount extends _i1.Mock ), returnValueForMissingStub: null, ); + @override _i2.Future<_i3.ApiResponse> fetchUnViewedNotificationsCount() => (super.noSuchMethod( diff --git a/test/widgets/siren_inbox_test.dart b/test/widgets/siren_inbox_test.dart index 555fadc..f8b5397 100644 --- a/test/widgets/siren_inbox_test.dart +++ b/test/widgets/siren_inbox_test.dart @@ -136,5 +136,17 @@ void main() { SirenDataProvider.instance.inboxController.sink .add(StreamResponse(result, UpdateEvents.READ_ALL, '')); }); + + testWidgets('Hide tab bar', (WidgetTester tester) async { + const widget = MaterialApp( + home: Scaffold( + body: SirenInbox( + hideTab: true, + ), + ), + ); + await tester.pumpWidget(widget); + expect(find.byType(TabBar), findsNothing); + }); }); } diff --git a/test/widgets/siren_inbox_test.mocks.dart b/test/widgets/siren_inbox_test.mocks.dart index 1e3ca38..6f46027 100644 --- a/test/widgets/siren_inbox_test.mocks.dart +++ b/test/widgets/siren_inbox_test.mocks.dart @@ -1,4 +1,4 @@ -// Mocks generated by Mockito 5.3.2 from annotations +// Mocks generated by Mockito 5.4.4 from annotations // in sirenapp_flutter_inbox/test/widgets/siren_inbox_test.dart. // Do not manually edit this file. @@ -6,10 +6,11 @@ import 'dart:async' as _i2; import 'package:mockito/mockito.dart' as _i1; +import 'package:mockito/src/dummies.dart' as _i6; import 'package:sirenapp_flutter_inbox/sirenapp_flutter_inbox.dart' as _i3; import 'package:sirenapp_flutter_inbox/src/api/fetch_unviewed_notification_count.dart' - as _i7; -import 'package:sirenapp_flutter_inbox/src/constants/generics.dart' as _i6; + as _i8; +import 'package:sirenapp_flutter_inbox/src/constants/generics.dart' as _i7; import 'package:sirenapp_flutter_inbox/src/data/siren_data_provider.dart' as _i5; import 'package:sirenapp_flutter_inbox/src/services/api_client.dart' as _i4; @@ -18,6 +19,8 @@ import 'package:sirenapp_flutter_inbox/src/services/api_client.dart' as _i4; // ignore_for_file: avoid_redundant_argument_values // ignore_for_file: avoid_setters_without_getters // ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member // ignore_for_file: prefer_const_constructors @@ -74,9 +77,16 @@ class MockSirenDataProvider extends _i1.Mock implements _i5.SirenDataProvider { @override String get userToken => (super.noSuchMethod( Invocation.getter(#userToken), - returnValue: '', - returnValueForMissingStub: '', + returnValue: _i6.dummyValue( + this, + Invocation.getter(#userToken), + ), + returnValueForMissingStub: _i6.dummyValue( + this, + Invocation.getter(#userToken), + ), ) as String); + @override set userToken(String? _userToken) => super.noSuchMethod( Invocation.setter( @@ -85,12 +95,20 @@ class MockSirenDataProvider extends _i1.Mock implements _i5.SirenDataProvider { ), returnValueForMissingStub: null, ); + @override String get recipientId => (super.noSuchMethod( Invocation.getter(#recipientId), - returnValue: '', - returnValueForMissingStub: '', + returnValue: _i6.dummyValue( + this, + Invocation.getter(#recipientId), + ), + returnValueForMissingStub: _i6.dummyValue( + this, + Invocation.getter(#recipientId), + ), ) as String); + @override set recipientId(String? _recipientId) => super.noSuchMethod( Invocation.setter( @@ -99,12 +117,20 @@ class MockSirenDataProvider extends _i1.Mock implements _i5.SirenDataProvider { ), returnValueForMissingStub: null, ); + @override String get apiDomain => (super.noSuchMethod( Invocation.getter(#apiDomain), - returnValue: '', - returnValueForMissingStub: '', + returnValue: _i6.dummyValue( + this, + Invocation.getter(#apiDomain), + ), + returnValueForMissingStub: _i6.dummyValue( + this, + Invocation.getter(#apiDomain), + ), ) as String); + @override set apiDomain(String? _apiDomain) => super.noSuchMethod( Invocation.setter( @@ -113,6 +139,7 @@ class MockSirenDataProvider extends _i1.Mock implements _i5.SirenDataProvider { ), returnValueForMissingStub: null, ); + @override _i2.StreamController<_i3.StreamResponse> get inboxController => (super.noSuchMethod( @@ -126,6 +153,7 @@ class MockSirenDataProvider extends _i1.Mock implements _i5.SirenDataProvider { Invocation.getter(#inboxController), ), ) as _i2.StreamController<_i3.StreamResponse>); + @override _i2.StreamController<_i3.StreamResponse> get iconController => (super.noSuchMethod( @@ -139,18 +167,21 @@ class MockSirenDataProvider extends _i1.Mock implements _i5.SirenDataProvider { Invocation.getter(#iconController), ), ) as _i2.StreamController<_i3.StreamResponse>); + @override - _i6.Status get tokenVerificationStatus => (super.noSuchMethod( + _i7.Status get tokenVerificationStatus => (super.noSuchMethod( Invocation.getter(#tokenVerificationStatus), - returnValue: _i6.Status.PENDING, - returnValueForMissingStub: _i6.Status.PENDING, - ) as _i6.Status); + returnValue: _i7.Status.PENDING, + returnValueForMissingStub: _i7.Status.PENDING, + ) as _i7.Status); + @override bool get isProviderInitialized => (super.noSuchMethod( Invocation.getter(#isProviderInitialized), returnValue: false, returnValueForMissingStub: false, ) as bool); + @override _i2.Future initialize() => (super.noSuchMethod( Invocation.method( @@ -160,6 +191,7 @@ class MockSirenDataProvider extends _i1.Mock implements _i5.SirenDataProvider { returnValue: _i2.Future.value(), returnValueForMissingStub: _i2.Future.value(), ) as _i2.Future); + @override void updateParams({ required String? userToken, @@ -176,14 +208,16 @@ class MockSirenDataProvider extends _i1.Mock implements _i5.SirenDataProvider { ), returnValueForMissingStub: null, ); + @override - void triggerError() => super.noSuchMethod( + void triggerEvent(_i7.UpdateEvents? event) => super.noSuchMethod( Invocation.method( - #triggerError, - [], + #triggerEvent, + [event], ), returnValueForMissingStub: null, ); + @override _i3.SirenErrorType getVerificationErrorType() => (super.noSuchMethod( Invocation.method( @@ -205,6 +239,7 @@ class MockSirenDataProvider extends _i1.Mock implements _i5.SirenDataProvider { ), ), ) as _i3.SirenErrorType); + @override void iconDispose() => super.noSuchMethod( Invocation.method( @@ -213,6 +248,7 @@ class MockSirenDataProvider extends _i1.Mock implements _i5.SirenDataProvider { ), returnValueForMissingStub: null, ); + @override void inboxDispose() => super.noSuchMethod( Invocation.method( @@ -227,7 +263,7 @@ class MockSirenDataProvider extends _i1.Mock implements _i5.SirenDataProvider { /// /// See the documentation for Mockito's code generation for more information. class MockFetchUnViewedNotificationsCount extends _i1.Mock - implements _i7.FetchUnViewedNotificationsCount { + implements _i8.FetchUnViewedNotificationsCount { @override _i4.ApiClient get api => (super.noSuchMethod( Invocation.getter(#api), @@ -240,6 +276,7 @@ class MockFetchUnViewedNotificationsCount extends _i1.Mock Invocation.getter(#api), ), ) as _i4.ApiClient); + @override set api(_i4.ApiClient? _api) => super.noSuchMethod( Invocation.setter( @@ -248,6 +285,7 @@ class MockFetchUnViewedNotificationsCount extends _i1.Mock ), returnValueForMissingStub: null, ); + @override _i2.Future<_i3.ApiResponse> fetchUnViewedNotificationsCount() => (super.noSuchMethod(