flutterdartflutter-notification

Notification on flutter


I'm trying to learn flutter, but I can't manage to do this. I'm doing a schedule about school that prints all your lessons etc. I want that when a lesson is about to start, a notification will be sent 5 minutes before that the lesson (or something) is about to start.The OS I want this to work is an IOS. Furthermore, I watched some videos using package:flutter_local_notifications/flutter_local_notifications.dart but nothing works on my code. If someone could help, I would be very grateful.

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

void main(){
  runApp(MaterialApp(home: MyApp()));
} 

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late Timer _timer;
  String _timeRemaining = '';

  @override
  void initState() {
    super.initState();
    _startTimer();
  }

  @override
  void dispose() {
    _timer.cancel();
    super.dispose();
  }

  void _startTimer() {
    _timer = Timer.periodic(const Duration(seconds: 1), (timer) {
      setState(() {
        _timeRemaining = _getTimeRemaining();
      });
    });
  }

String _getTimeRemaining() {
  DateTime now = DateTime.now();
  DateTime tomorrow = DateTime(now.year, now.month, now.day + 1);
  DateTime nextLesson = _getNextLessonTime();
  Duration difference = nextLesson.difference(now);
  if (difference.isNegative) {
    nextLesson = _getNextLessonTime();
    difference = nextLesson.difference(now);
  }
  int seconds = difference.inSeconds % 60;
  int minutes = (difference.inMinutes % 60);
  int hours = difference.inHours % 24;
  String nextLessonName = _getNextLessonName(nextLesson);
  String timeRemaining;
  if (now.weekday == DateTime.sunday) {
    timeRemaining = 'Non si va a scuola oggi.';
  }else if(tomorrow.weekday == DateTime.sunday){
    timeRemaining = 'Non si va a scuola domani.';
  } else if (now.weekday == DateTime.saturday && now.hour >= 12) {
    timeRemaining = 'La giornata scolastica è finita.';
  }else if (now.hour >= 14){
      timeRemaining = 'La giornata scolastica è finita.';
  } else if (difference.inHours >= 24) {
    timeRemaining = 'Prossima lezione\n $nextLessonName il ${nextLesson.day}/${nextLesson.month}/${nextLesson.year} fra ${difference.inDays} giorni.';
  } else if (now.hour >= nextLesson.hour && now.minute >= nextLesson.minute) {
    nextLesson = _getNextLessonTime();
    difference = nextLesson.difference(now);
    seconds = difference.inSeconds % 60;
    minutes = (difference.inMinutes % 60);
    hours = difference.inHours % 24;
    nextLessonName = _getNextLessonName(nextLesson);
    timeRemaining = 'Prossima lezione\n $nextLessonName fra ${hours.toString().padLeft(2, '0')}:${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}.';
  } else {
    timeRemaining = 'Prossima lezione\n $nextLessonName fra ${hours.toString().padLeft(2, '0')}:${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}.';
  }
  return timeRemaining;
}

  DateTime _getNextLessonTime() {
    DateTime now = DateTime.now();
    DateTime nextLesson;
    if (now.weekday == DateTime.saturday) {
      nextLesson = DateTime(now.year, now.month, now.day, 10, 0);
    } else {
      nextLesson = DateTime(now.year, now.month, now.day, 8, 0);
      if (now.hour >= 14) {
        nextLesson = nextLesson.add(const Duration(days: 1));
      }
    }
    return nextLesson;
  }

  String _getNextLessonName(DateTime nextLesson) {
    String nextLessonName = '';
    if (nextLesson.weekday == DateTime.monday) {
      nextLessonName = 'Telecomunicazioni';
    } else if (nextLesson.weekday == DateTime.tuesday || nextLesson.weekday == DateTime.wednesday) {
      nextLessonName = 'Italiano';
    } else if (nextLesson.weekday == DateTime.thursday) {
      nextLessonName = 'Sistemi';
    } else if (nextLesson.weekday == DateTime.friday) {
      nextLessonName = 'Matematica';
    } else if (nextLesson.weekday == DateTime.saturday) {
      nextLessonName = 'Telecomunicazioni';
    }
    return nextLessonName;
  }

@override
Widget build(BuildContext context) {
  return MaterialApp(
    title: 'Orario',
    home: Scaffold(
      appBar: AppBar(
        title: const Text('Orario'),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Center(
              child: Text(
                _timeRemaining,
                style: const TextStyle(fontSize: 20),
                textAlign: TextAlign.center,
              ),
            ),
            const SizedBox(height: 20),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                _buildDayButton('Lunedi', context),
                _buildDayButton('Martedi', context),
              ],
            ),
            const SizedBox(height: 20),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                _buildDayButton('Mercoledi', context),
                _buildDayButton('Giovedi', context),
              ],
            ),
            const SizedBox(height: 20),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                _buildDayButton('Venerdi', context),
                _buildDayButton('Sabato', context),
              ],
            ),
            const SizedBox(height: 20),
            const Text(
              'Programma fatto da Skerdi Velo',
              style: TextStyle(fontSize: 12),
            ),
          ],
        ),
      ),
    ),
  );
}

  Widget _buildDayButton(String day, BuildContext context) {
    String schedule = '';
    switch (day) {
      case 'Lunedi':
        schedule = '08:00-09:00 Telecomunicazioni\n09:00-10:00 Matematica\n10:00-12:00 Italiano\n12:00-13:00 Inglese';
        break;
      case 'Martedi':
        schedule = '08:00-09:00 Italiano\n09:00-10:00 Sistemi\n10:00-11:00 Sistemi\n11:00-12:00 Informatica\n12:00-13:00 Informatica\n13:00-14:00 Informatica';
        break;
      case 'Mercoledi':
        schedule = '08:00-09:00 Italiano\n09:00-10:00 Storia\n10:00-11:00 Informatica\n11:00-12:00 Educazione Fisica\n12:00-13:00 Matematica\n13:00-14:00 Inglese';
        break;
      case 'Giovedi':
        schedule = '08:00-09:00 Sistemi\n09:00-10:00 Matematica\n10:00-11:00 Storia\n11:00-12:00 Informatica\n12:00-13:00 Inglese\n13:00-14:00 T.P.I.';
        break;
      case 'Venerdi':
        schedule = '08:00-09:00 Matematica\n09:00-10:00 Sistemi\n10:00-11:00 Informatica\n11:00-12:00 Educazione Fisica';
        break;
      case 'Sabato':
        schedule = '08:00-09:00 Telecomunicazioni\n09:00-10:00 Telecomunicazioni\n10:00-11:00 T.P.I.\n11:00-12:00 T.P.I.';
        break;
    }

    return ElevatedButton(
      onPressed: () {
        if (schedule.isNotEmpty) {
          _showAlertDialog(context, day, schedule);
        }
      },
      style: ElevatedButton.styleFrom(
        minimumSize: const Size(150, 50),
      ),
      child: Text(
        day,
        style: const TextStyle(fontSize: 20),
      ),
    );
  }

  void _showAlertDialog(BuildContext context, String day, String schedule) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text(day),
          content: Text(schedule),
          actions: [
            TextButton(
              onPressed: () {
                Navigator.of(context).pop();
              },
              child: const Text('OK'),
            ),
          ],
        );
      },
    );
  }
}

Solution

  • This is an implementation which will allow you to schedule notifications using Flutter on IOS.

    Imports

    import 'package:flutter_local_notifications/flutter_local_notifications.dart';
    import 'package:flutter_native_timezone/flutter_native_timezone.dart';
    import 'package:flutter_push_notifications/utils/download_util.dart';
    import 'package:rxdart/subjects.dart';
    import 'package:timezone/data/latest_all.dart' as tz;
    import 'package:timezone/timezone.dart' as tz;
    

    Initializing the notification service

    class NotificationService {
      NotificationService();
    
      final _localNotifications = FlutterLocalNotificationsPlugin();
      final BehaviorSubject<String> behaviorSubject = BehaviorSubject();
    
        final IOSInitializationSettings initializationSettingsIOS =
            IOSInitializationSettings(
                requestSoundPermission: true,
                requestBadgePermission: true,
                requestAlertPermission: true,
                onDidReceiveLocalNotification: onDidReceiveLocalNotification);
    
        final InitializationSettings initializationSettings =
            InitializationSettings(
          android: initializationSettingsAndroid,
          iOS: initializationSettingsIOS,
        );
    
        await _localNotifications.initialize(initializationSettings,
            onSelectNotification: selectNotification);
      }
    
      void onDidReceiveLocalNotification(
          int id, String? title, String? body, String? payload) {
        print('id $id');
      }
    
      void selectNotification(String? payload) {
        if (payload != null && payload.isNotEmpty) {
          behaviorSubject.add(payload);
        }
      }
    }
    
    
    Future<NotificationDetails> _notificationDetails() async {
      final bigPicture = await DownloadUtil.downloadAndSaveFile(
          "https://images.unsplash.com/photo-1624948465027-6f9b51067557?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80",
          "drinkwater");
    
      IOSNotificationDetails iosNotificationDetails = IOSNotificationDetails(
          threadIdentifier: "thread1",
          attachments: <IOSNotificationAttachment>[
            IOSNotificationAttachment(bigPicture)
          ]);
    
      final details = await _localNotifications.getNotificationAppLaunchDetails();
      if (details != null && details.didNotificationLaunchApp) {
        behaviorSubject.add(details.payload!);
      }
      NotificationDetails platformChannelSpecifics = NotificationDetails(
          android: androidPlatformChannelSpecifics, iOS: iosNotificationDetails);
    
      return platformChannelSpecifics;
    }
    

    Set a timezone. Depends on your functionality if you even need it.

    tz.initializeTimeZones();
      tz.setLocalLocation(
        tz.getLocation(
          await FlutterNativeTimezone.getLocalTimezone(),
        ),
      );
    

    Finally, the method to schedule a notification. You can subtract the current date from a future date with some offset to find the amount of seconds you need to enter.

    Future<void> showScheduledLocalNotification({
      required int id,
      required String title,
      required String body,
      required String payload,
      required int seconds,
    }) async {
      final platformChannelSpecifics = await _notificationDetails();
      await _localNotifications.zonedSchedule(
        id,
        title,
        body,
        tz.TZDateTime.now(tz.local).add(Duration(seconds: seconds)),
        platformChannelSpecifics,
        payload: payload,
        uiLocalNotificationDateInterpretation:
            UILocalNotificationDateInterpretation.absoluteTime,
        androidAllowWhileIdle: true,
      );
    }
    

    This article gives a thorough guide: https://blog.codemagic.io/flutter-local-notifications/ This answer mostly highlighted what you needed for your implementation.