Flutter GB App Notifications
A comprehensive, flexible, and robust solution for handling in-app notifications in Flutter applications. This package seamlessly handles fetching, displaying, and managing notification states (read, unread, archived). It offers flexible configuration options and customizable UI components to quickly integrate a fully functional notification center into your app.
Table of Contents
- Features
- Installation
- Configuration (
AppNotificationConfig) - Custom Notification Metadata
- Presentation Widgets API
- Customizing List UI (
AppNotificationsListTemplateStyle) - Dependency Injection
- Contributing
Features
- Ready-to-use Notification Center UI: Provides list templates and full-page templates.
- Swipe Actions: Swipe to mark as read or to archive (
flutter_slidablebuilt-in). - Unread Badge Icon: Automatically updating bell icon with a notification count.
- Custom Metadata Parsing: Type-safe custom metadata loading and parsing.
- Flexible Data Sources: Highly customizable endpoint builders to match any backend shape.
- Robust State Management: Built-in BLoC implementation manages fetching, polling or error states gracefully.
Installation
Add the following to your pubspec.yaml file:
dependencies:
flutter_gb_app_notifications: ^0.17.0
Run flutter pub get to install the package.
Note: Ensure you have flutter_slidable (version ^2.0.0 or higher) as a dependency in your project, as it's used for swipe actions in the notification list.
Configuration (AppNotificationConfig)
The AppNotificationConfig class is central to configuring the library's behavior, especially how it interacts with your backend API. You must register an instance of AppNotificationConfig using the dependency injection setup.
Here's an example of how to configure AppNotificationConfig:
import 'package:flutter_gb_app_notifications/flutter_gb_app_notifications.dart';
import 'package:http/http.dart'; // For Response and Request types
final AppNotificationConfig appNotificationConfig = AppNotificationConfig(
getListApiEndpoint: (params) {
// Endpoint to fetch a list of notifications
return Uri.parse("https://api.example.com/notifications")
.replace(queryParameters: (params ?? {})..addAll({"sort": "-createdAt"}));
},
getUnreadCountApiEndpoint: (params) {
// Endpoint to fetch the count of unread notifications
return Uri.parse("https://api.example.com/notifications/unread-count")
.replace(queryParameters: params);
},
markAsReadCompleteApiEndpoint: (notification) {
// Optional: Endpoint to mark a specific notification as read
return Uri.parse("https://api.example.com/notifications/${notification.id}/read");
},
archiveApiEndpoint: (notification) {
// Optional: Endpoint to archive a specific notification
return Uri.parse("https://api.example.com/notifications/${notification.id}/archive");
},
archiveAllApiEndpoint: () {
// Optional: Endpoint to archive all notifications
return Uri.parse("https://api.example.com/notifications/archive-all");
},
getListResponseParser: (response) {
// Optional: Custom parser for the list of notifications API response
// Example: return (json.decode(response.body) as List).map((e) => AppNotification.fromJson(e)).toList();
return []; // Implement your parsing logic here
},
getCountResponseParser: (response) {
// Optional: Custom parser for the unread count API response
// Example: return json.decode(response.body)['count'] as int;
return 0; // Implement your parsing logic here
},
metadataMapper: (map) {
// Optional: Custom mapper for notification metadata.
// Use this to deserialize custom metadata types based on a 'type' field or similar.
// Example:
// String? type = map["type"];
// switch (type) {
// case "followed_user_creation":
// return FollowedUserCreationNotificationMetadataModel.fromMap(map);
// default:
// return AppNotificationMetadataModel.fromMap(map);
// }
return AppNotificationMetadataModel.fromMap(map); // Default or custom logic
},
markAsReadRequestMapper: (request, notification) {
// Optional: Customize the request for marking a notification as read
// return request.copyWith(headers: {'X-Custom-Header': 'value'});
return request;
},
archiveRequestMapper: (request, notification) {
// Optional: Customize the request for archiving a notification
// return request.copyWith(body: json.encode({'status': 'archived'}));
return request;
},
archiveAllRequestMapper: (request) {
// Optional: Customize the request for archiving all notifications
// return request.copyWith(method: 'POST');
return request;
},
);
Configuration Options
| Field | Type | Description |
|---|---|---|
getUnreadCountApiEndpoint |
Uri Function(Map<String, dynamic>? params) |
Required. Provides the API endpoint to fetch the unread notification count. |
getListApiEndpoint |
Uri Function(Map<String, dynamic>? params) |
Required. Provides the API endpoint to fetch the list of notifications. |
markAsReadCompleteApiEndpoint |
Uri Function(AppNotification)? |
Optional. API endpoint to mark a specific notification as read. |
archiveApiEndpoint |
Uri Function(AppNotification)? |
Optional. API endpoint to archive a specific notification. |
archiveAllApiEndpoint |
Uri Function()? |
Optional. API endpoint to archive all notifications. |
getListResponseParser |
List<AppNotification> Function(Response)? |
Optional. A custom function to parse the API response for the list of notifications. |
getCountResponseParser |
int Function(Response)? |
Optional. A custom function to parse the unread notification count. |
metadataMapper |
NotificationMetadataMapper? |
Optional. A custom function to map raw JSON metadata to your custom AppNotificationMetadata. |
markAsReadRequestMapper |
BaseRequest Function(Request, AppNotification)? |
Optional. Customize the HTTP request before sending it to mark as read. |
archiveRequestMapper |
BaseRequest Function(Request, AppNotification)? |
Optional. Customize the HTTP request before sending it to archive. |
archiveAllRequestMapper |
BaseRequest Function(Request)? |
Optional. Customize the HTTP request before sending it to archive all. |
Custom Notification Metadata
You can extend AppNotificationMetadata to define custom metadata for your notifications. This is useful for handling different types of notifications with specific data. For serialization, it's recommended to use built_value.
-
Define your custom metadata class:
// lib/domain/entities/custom_app_notification_metadata.dart abstract class FollowedUserCreationNotificationMetadata implements AppNotificationMetadata { String? get resourceId; String? get resourceName; String? get ownerUsername; } -
Create a
built_valuemodel for your metadata:// lib/infrastructure/models/custom_app_notification_metadata_model.dart import 'dart:convert'; import 'package:built_value/built_value.dart'; import 'package:built_value/serializer.dart'; import 'package:flutter_gb_app_notifications/flutter_gb_app_notifications.dart'; part 'custom_app_notification_metadata_model.g.dart'; abstract class FollowedUserCreationNotificationMetadataModel implements FollowedUserCreationNotificationMetadata, Built<FollowedUserCreationNotificationMetadataModel, FollowedUserCreationNotificationMetadataModelBuilder> { FollowedUserCreationNotificationMetadataModel._(); factory FollowedUserCreationNotificationMetadataModel( [void Function(FollowedUserCreationNotificationMetadataModelBuilder) updates]) = _$FollowedUserCreationNotificationMetadataModel; static FollowedUserCreationNotificationMetadataModel fromMap(Map<String, dynamic> map) { // Ensure you have a global serializers instance accessible, e.g., appSerializers return appSerializers.deserializeWith(FollowedUserCreationNotificationMetadataModel.serializer, map)!; } static Serializer<FollowedUserCreationNotificationMetadataModel> get serializer => _$followedUserCreationNotificationMetadataModelSerializer; } -
Register your custom metadata model with your project's
Serializers:// lib/infrastructure/models/serializers.dart @SerializersFor([ AppNotificationMetadata, FollowedUserCreationNotificationMetadataModel, ]) final Serializers appSerializers = (_$appSerializers.toBuilder()).build(); -
Implement
metadataMapperinAppNotificationConfig: As shown in theAppNotificationConfigexample, provide ametadataMapperfunction that inspects the raw notification map and returns the appropriate customAppNotificationMetadatainstance.
Presentation Widgets API
The library provides several widgets to help you display and manage notifications in your UI.
GBNotificationBadgeBuilder
A widget that displays an icon (e.g., a bell) with an unread notification count badge. It automatically fetches and updates the unread count.
import 'package:flutter/material.dart';
import 'package:flutter_gb_app_notifications/flutter_gb_app_notifications.dart';
class MyNotificationIcon extends StatelessWidget {
const MyNotificationIcon({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return GBNotificationBadgeBuilder.bellIcon(
size: 30,
iconColor: Colors.blue,
badgeColor: Colors.red,
onTap: () {
// Navigate to the notifications page
},
);
}
}
AppNotificationBuilder
A BlocBuilder wrapper that rebuilds its child widget whenever the AppNotificationState changes. Useful for custom UIs.
AppNotificationBuilder(
builder: (context, state) {
if (state.isLoading) return const CircularProgressIndicator();
if (state.notifications.isEmpty) return const Text('No notifications');
return ListView.builder(
itemCount: state.notifications.length,
itemBuilder: (context, index) {
final notification = state.notifications[index];
return ListTile(title: Text(notification.title));
},
);
},
)
GBAppNotificationsListTemplate
A pre-built widget that displays a list of notifications with swipe-to-action (mark as read, archive) functionality, pull-to-refresh, and empty/error states.
GBAppNotificationsListTemplate(
style: AppNotificationsListTemplateStyle(
enableArchive: true,
enableMarkAsRead: true,
onItemTap: (notification) {
print('Tapped on notification: ${notification.title}');
},
onEmptyBuilder: (context, constraints) {
return const Center(child: Text('You have no new alerts.'));
},
),
)
GBNotificationPageTemplate
A full-page template for displaying notifications, embedding GBAppNotificationsListTemplate and adding a customizable AppBar.
GBNotificationPageTemplate(
titlePage: 'My App Notifications',
backgroundColor: Colors.grey[100],
titleColor: Colors.black,
style: AppNotificationsListTemplateStyle(
enableArchive: true,
),
);
Customizing List UI (AppNotificationsListTemplateStyle)
AppNotificationsListTemplateStyle provides numerous configurations.
| Field | Type | Description |
|---|---|---|
enableMarkAsRead |
bool |
Enables swipe-to-mark-as-read action. (Default: true) |
enableArchive |
bool |
Enables swipe-to-archive action. (Default: true) |
enableItemSeparator |
bool |
Renders a separator between list items. (Default: true) |
itemContentBuilder |
AnimatedStateListItemBuilder<AppNotification>? |
A custom builder for the content of each notification item. |
separatorBuilder |
AnimatedStateListItemBuilder<AppNotification>? |
A custom builder for the item separator. |
onItemTap |
void Function(AppNotification)? |
Callback when a notification item is tapped. |
autoReadOnTap |
bool |
Automatically marks notification as read upon tap. (Default: true) |
onEmptyBuilder |
Widget Function(BuildContext, BoxConstraints)? |
Custom builder for the empty list state. |
filterCallback |
bool Function(AppNotification)? |
Filter callback for the notification list. |
headerBuilder |
Widget Function(BuildContext)? |
Custom builder for a header widget (must return a Sliver). |
Dependency Injection
The library requires get_it for dependency injection. Call configureAppNotificationInjection to register necessary services.
import 'package:flutter_gb_stack_base/flutter_gb_stack_base.dart';
import 'package:get_it/get_it.dart';
import 'package:flutter_gb_app_notifications/flutter_gb_app_notifications.dart';
final getItNotifications = GetIt.instance;
Future<void> configureAppNotificationInjection(
AppEnvironment environment,
AppNotificationConfig config,
) async {
if (!getItNotifications.isRegistered<AppNotificationConfig>()) {
getItNotifications.registerSingleton<AppNotificationConfig>(config);
}
getItNotifications.registerSingletonAsync<NotificationService>(
() async {
return NotificationServiceImpl(
httpClient: getItNotifications(),
notificationConfig: config,
);
},
dependsOn: [
if (AppEnvironment.test != environment) IHttpClient,
],
);
await getItNotifications.isReady<NotificationService>();
}
Usage:
Initialize dependencies early in your application lifecycle.
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Register your core dependencies (e.g., IHttpClient)
// configureCoreDependencies();
// Configure App Notifications
await configureAppNotificationInjection(
AppEnvironment.development,
appNotificationConfig, // Your AppNotificationConfig instance
);
runApp(const MyApp());
}
Contributing
Contributions are welcome! Please create an issue or submit a pull request if you find a bug or want to propose an enhancement. Ensure tests run successfully and maintain the current code style.
Libraries
- application/application
- application/bloc/bloc
- application/bloc/containers/containers
- application/bloc/containers/notification_item_container/notification_item_container_bloc
- application/bloc/shared/app_notification/app_notification_bloc
- config/app_notification_config
- config/app_notification_list_template_style
- config/app_notification_page_template_style
- config/config
- dependency_injection
- domain/domain
- domain/entities/app_notification
- domain/entities/entities
- domain/services/notification_service
- domain/services/services
- flutter_gb_app_notifications
- infrastructure/infrastructure
- infrastructure/models/app_notification_model
- infrastructure/models/models
- infrastructure/models/serializers
- infrastructure/services/app_notification_service_impl
- infrastructure/services/services
- presentation/container/app_notification_builder
- presentation/container/containers
- presentation/container/notification_icon
- presentation/container/notification_list_template
- presentation/container/notification_listener_bloc
- presentation/container/notification_provider
- presentation/pages/notification_page_template
- presentation/pages/pages
- presentation/presentations
- utils/notification_logger
- utils/utils