Files
SDKmuta/lib/services/notification_service.dart
T

170 lines
5.8 KiB
Dart

import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:timezone/timezone.dart' as tz;
import 'package:timezone/data/latest.dart' as tz;
import 'package:flutter_timezone/flutter_timezone.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../services/google_calendar_service.dart';
class NotificationService {
static final NotificationService _instance = NotificationService._internal();
factory NotificationService() => _instance;
NotificationService._internal();
final FlutterLocalNotificationsPlugin _plugin = FlutterLocalNotificationsPlugin();
bool _initialized = false;
static const _channel = AndroidNotificationChannel(
'shooting_app_events',
'Event Reminders',
description: 'Notifications for upcoming shooting events',
importance: Importance.max,
playSound: true,
enableVibration: true,
);
NotificationDetails get _notifDetails => const NotificationDetails(
android: AndroidNotificationDetails(
'shooting_app_events',
'Event Reminders',
channelDescription: 'Notifications for upcoming shooting events',
importance: Importance.max,
priority: Priority.high,
icon: '@drawable/ic_stat_icon_white',
),
iOS: DarwinNotificationDetails(
presentAlert: true,
presentBadge: true,
presentSound: true,
),
);
Future<void> initialize() async {
if (_initialized) return;
_initialized = true; // set early to prevent re-entry
try {
tz.initializeTimeZones();
final String timezoneName = await FlutterTimezone.getLocalTimezone();
tz.setLocalLocation(tz.getLocation(timezoneName));
} catch (_) {}
try {
const androidSettings = AndroidInitializationSettings('@mipmap/ic_launcher');
const iosSettings = DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
);
const initSettings = InitializationSettings(android: androidSettings, iOS: iosSettings);
await _plugin.initialize(initSettings);
final androidPlugin = _plugin.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>();
await androidPlugin?.createNotificationChannel(_channel);
await requestPermissions();
} catch (_) {}
}
Future<bool> requestPermissions() async {
final android = _plugin.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>();
final ios = _plugin.resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin>();
bool granted = false;
if (android != null) {
granted = await android.requestNotificationsPermission() ?? false;
}
if (ios != null) {
granted = await ios.requestPermissions(alert: true, badge: true, sound: true) ?? false;
}
return granted;
}
Future<void> cancelAll() async {
await _plugin.cancelAll();
}
Future<void> scheduleEventNotifications(List<CalendarEvent> events) async {
try {
await initialize();
final prefs = await SharedPreferences.getInstance();
final hours = prefs.getInt('notificationHours_single') ?? 1;
final notifyDezuranje = prefs.getBool('notifyDezuranje') ?? true;
final notifySestanek = prefs.getBool('notifySestanek') ?? true;
final notifyTekma = prefs.getBool('notifyTekma') ?? true;
final isSlovenian = (prefs.getString('language') ?? 'English') == 'Slovenian';
final now = DateTime.now();
await _plugin.cancelAll();
int notifId = 0;
for (final event in events) {
if (event.startTime == null) continue;
final summary = (event.summary ?? '').toLowerCase();
final isCompetition = summary.contains('liga') || summary.contains('tekmovanje');
final isSestanek = summary.contains('sestanek');
final isDezuranje = !isCompetition && !isSestanek;
if (isCompetition && !notifyTekma) continue;
if (isSestanek && !notifySestanek) continue;
if (isDezuranje && !notifyDezuranje) continue;
final notifyAt = event.startTime!.subtract(Duration(hours: hours));
if (notifyAt.isAfter(now)) {
await _scheduleNotification(
id: notifId++,
title: event.summary ?? 'Event',
body: isSlovenian
? (hours == 1 ? 'Začne se čez 1 uro' : 'Začne se čez $hours ur')
: (hours == 1 ? 'Starts in 1 hour' : 'Starts in $hours hours'),
scheduledDate: notifyAt,
);
}
}
} catch (_) {}
}
Future<void> scheduleTestNotification() async {
try {
await initialize();
final prefs = await SharedPreferences.getInstance();
final isSlovenian = (prefs.getString('language') ?? 'English') == 'Slovenian';
await _plugin.show(
9999,
isSlovenian ? 'Testno obvestilo' : 'Test Notification',
isSlovenian ? 'Obvestila delujejo!' : 'Notifications are working!',
_notifDetails,
);
final in10s = DateTime.now().add(const Duration(seconds: 10));
await _scheduleNotification(
id: 9998,
title: isSlovenian ? 'Načrtovano testno obvestilo' : 'Scheduled Test',
body: isSlovenian ? 'Načrtovana obvestila delujejo!' : 'Scheduled notifications are working!',
scheduledDate: in10s,
);
} catch (_) {}
}
Future<void> _scheduleNotification({
required int id,
required String title,
required String body,
required DateTime scheduledDate,
}) async {
final tzDate = tz.TZDateTime.from(scheduledDate, tz.local);
await _plugin.zonedSchedule(
id,
title,
body,
tzDate,
_notifDetails,
androidScheduleMode: AndroidScheduleMode.inexactAllowWhileIdle,
uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime,
);
}
}