haveno-app/lib/services/local_notification_service.dart
2024-12-08 06:38:57 +00:00

249 lines
No EOL
8.3 KiB
Dart

// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:haveno/profobuf_models.dart';
import 'package:haveno_app/main.dart';
import 'package:haveno_app/views/screens/dispute_chat_screen.dart';
import 'package:haveno_app/views/screens/home_screen.dart';
import 'package:haveno_app/views/screens/trade_chat_screen.dart';
import 'package:timezone/timezone.dart' as tz;
import 'package:timezone/data/latest_all.dart' as tz;
class LocalNotificationsService {
final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
final int foregroundServiceNotificationId = 888;
bool _initialized = false;
static final LocalNotificationsService _instance = LocalNotificationsService._internal();
factory LocalNotificationsService() => _instance;
LocalNotificationsService._internal();
Future<void> init() async {
if (_initialized) return; // Prevent re-initialization
_initialized = true;
print("Initializing Timezones...");
tz.initializeTimeZones();
print("Timezones Initialized.");
const LinuxInitializationSettings initializationSettingsLinux =
LinuxInitializationSettings(defaultActionName: 'Haveno');
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('@mipmap/ic_launcher');
const DarwinInitializationSettings initializationSettingsDarwin =
DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
);
const DarwinInitializationSettings macOsInitializationSettingsDarwin =
DarwinInitializationSettings(
requestAlertPermission: false,
requestBadgePermission: false,
requestSoundPermission: false,
);
const InitializationSettings initializationSettings = InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsDarwin,
macOS: macOsInitializationSettingsDarwin,
linux: initializationSettingsLinux
);
print("Initializing FlutterLocalNotificationsPlugin...");
await _flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveNotificationResponse: _onNotificationResponse,
);
print("FlutterLocalNotificationsPlugin Initialized.");
}
Future<void> showForegroundServiceNotification({
required String title,
required String body,
String? payload,
}) async {
const AndroidNotificationDetails androidPlatformChannelSpecifics =
AndroidNotificationDetails(
'haveno',
'Haveno Plus Service',
channelDescription: 'Haveno service running in the background',
importance: Importance.max,
priority: Priority.high,
ticker: 'ticker',
ongoing: true,
);
const DarwinNotificationDetails iOSPlatformChannelSpecifics = DarwinNotificationDetails();
const DarwinNotificationDetails macOSPlatformChannelSpecifics = DarwinNotificationDetails();
const NotificationDetails platformChannelSpecifics = NotificationDetails(
android: androidPlatformChannelSpecifics,
iOS: iOSPlatformChannelSpecifics,
macOS: macOSPlatformChannelSpecifics
);
await _flutterLocalNotificationsPlugin.show(
foregroundServiceNotificationId,
title,
body,
platformChannelSpecifics,
payload: payload,
);
}
Future<void> updateForegroundServiceNotification({
required String title,
required String body,
String? payload,
}) async {
await showForegroundServiceNotification(title: title, body: body, payload: payload);
}
Future<void> showNotification({
required int id,
required String title,
required String body,
String? payload,
}) async {
const AndroidNotificationDetails androidPlatformChannelSpecifics =
AndroidNotificationDetails(
'haveno_notifications',
'Haveno Plus Notifications',
channelDescription: 'Notifications for Haveno Plus events',
importance: Importance.max,
priority: Priority.high,
ticker: 'ticker',
);
const DarwinNotificationDetails iOSPlatformChannelSpecifics = DarwinNotificationDetails();
const DarwinNotificationDetails macOSPlatformChannelSpecifics = DarwinNotificationDetails(
presentAlert: true,
presentSound: true
);
const NotificationDetails platformChannelSpecifics = NotificationDetails(
android: androidPlatformChannelSpecifics,
iOS: iOSPlatformChannelSpecifics,
macOS: macOSPlatformChannelSpecifics
);
await _flutterLocalNotificationsPlugin.show(
id,
title,
body,
platformChannelSpecifics,
payload: payload,
);
}
Future<void> scheduleNotification({
required int id,
required String title,
required String body,
required DateTime scheduledDate,
String? payload,
}) async {
final tz.TZDateTime tzScheduledDate = tz.TZDateTime.from(scheduledDate, tz.local);
const AndroidNotificationDetails androidPlatformChannelSpecifics =
AndroidNotificationDetails(
'haveno_notifications',
'Haveno Plus Notifications',
channelDescription: 'Notifications for Haveno Plus events',
importance: Importance.max,
priority: Priority.high,
ticker: 'ticker',
);
const DarwinNotificationDetails iOSPlatformChannelSpecifics =
DarwinNotificationDetails();
const NotificationDetails platformChannelSpecifics = NotificationDetails(
android: androidPlatformChannelSpecifics,
iOS: iOSPlatformChannelSpecifics,
);
await _flutterLocalNotificationsPlugin.zonedSchedule(
id,
title,
body,
tzScheduledDate,
platformChannelSpecifics,
payload: payload,
androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime,
);
}
Future<void> cancelNotification(int id) async {
await _flutterLocalNotificationsPlugin.cancel(id);
}
Future<void> cancelAllNotifications() async {
await _flutterLocalNotificationsPlugin.cancelAll();
}
void _onNotificationResponse(NotificationResponse notificationResponse) async {
print('Notification tapped with payload: ${notificationResponse.payload}');
var object = jsonDecode(notificationResponse.payload!);
switch (object['action']) {
case 'route_to_chat_screen':
//print(object['chateProtobufAsJson']);
var chatMessage = ChatMessage()..mergeFromProto3Json(jsonDecode(object['chatMessageProtobufAsJson']));
if (chatMessage.tradeId.isNotEmpty) {
if (chatMessage.type != SupportType.TRADE) {
navigatorKey.currentState?.push(
MaterialPageRoute(builder: (context) => DisputeChatScreen(tradeId: chatMessage.tradeId))
);
} else {
navigatorKey.currentState?.push(
MaterialPageRoute(builder: (context) => TradeChatScreen(tradeId: chatMessage.tradeId))
);
}
break;
}
case 'route_to_active_trades_screen':
navigatorKey.currentState?.push(
MaterialPageRoute(builder: (context) => HomeScreen(initialIndex: 3))
);
break;
default:
print('Unknown action: ${object['action']}');
break;
}
}
}