110 lines
3.2 KiB
Dart
110 lines
3.2 KiB
Dart
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
|
import 'package:app_badge_plus/app_badge_plus.dart';
|
|
import 'package:permission_handler/permission_handler.dart';
|
|
|
|
/// Central service for all local notification and badge operations.
|
|
/// Call [initialize] once in main(), then use [showNotification] and [setBadge].
|
|
class NotificationService {
|
|
static final NotificationService _instance = NotificationService._internal();
|
|
factory NotificationService() => _instance;
|
|
NotificationService._internal();
|
|
|
|
static const String _channelId = 'mapan_loyalty_channel';
|
|
static const String _channelName = 'Mie Mapan Promos';
|
|
static const String _channelDescription =
|
|
'Notifications for new promos and loyalty rewards from Mie Mapan.';
|
|
|
|
final FlutterLocalNotificationsPlugin _flnp = FlutterLocalNotificationsPlugin();
|
|
|
|
bool _initialized = false;
|
|
|
|
Future<void> initialize() async {
|
|
if (_initialized) return;
|
|
|
|
const androidInit = AndroidInitializationSettings('@mipmap/ic_launcher');
|
|
const darwinInit = DarwinInitializationSettings(
|
|
requestAlertPermission: false,
|
|
requestBadgePermission: false,
|
|
requestSoundPermission: false,
|
|
);
|
|
const initSettings = InitializationSettings(
|
|
android: androidInit,
|
|
iOS: darwinInit,
|
|
);
|
|
|
|
await _flnp.initialize(
|
|
settings: initSettings,
|
|
);
|
|
await _createNotificationChannel();
|
|
_initialized = true;
|
|
}
|
|
|
|
Future<void> _createNotificationChannel() async {
|
|
const channel = AndroidNotificationChannel(
|
|
_channelId,
|
|
_channelName,
|
|
description: _channelDescription,
|
|
importance: Importance.max,
|
|
);
|
|
await _flnp
|
|
.resolvePlatformSpecificImplementation<
|
|
AndroidFlutterLocalNotificationsPlugin>()
|
|
?.createNotificationChannel(channel);
|
|
}
|
|
|
|
/// Request POST_NOTIFICATIONS permission on Android 13+.
|
|
Future<void> requestPermission() async {
|
|
if (await Permission.notification.isDenied) {
|
|
await Permission.notification.request();
|
|
}
|
|
}
|
|
|
|
/// Show a single notification in the device tray.
|
|
Future<void> showNotification({
|
|
required int id,
|
|
required String title,
|
|
required String body,
|
|
}) async {
|
|
await initialize();
|
|
const androidDetails = AndroidNotificationDetails(
|
|
_channelId,
|
|
_channelName,
|
|
channelDescription: _channelDescription,
|
|
importance: Importance.max,
|
|
priority: Priority.high,
|
|
icon: '@mipmap/ic_launcher',
|
|
);
|
|
const iosDetails = DarwinNotificationDetails(
|
|
presentAlert: true,
|
|
presentBadge: true,
|
|
presentSound: true,
|
|
);
|
|
const details = NotificationDetails(
|
|
android: androidDetails,
|
|
iOS: iosDetails,
|
|
);
|
|
await _flnp.show(
|
|
id: id,
|
|
title: title,
|
|
body: body,
|
|
notificationDetails: details,
|
|
);
|
|
}
|
|
|
|
/// Set the badge count on the app icon.
|
|
Future<void> setBadge(int count) async {
|
|
try {
|
|
final supported = await AppBadgePlus.isSupported();
|
|
if (supported) {
|
|
await AppBadgePlus.updateBadge(count);
|
|
}
|
|
} catch (e) {
|
|
debugPrint('Badge update error: $e');
|
|
}
|
|
}
|
|
|
|
/// Clear the badge count (set to 0).
|
|
Future<void> clearBadge() => setBadge(0);
|
|
}
|