1

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'),
            ),
          ],
        );
      },
    );
  }
}
Skerdi Velo
  • 121
  • 2
  • 13

1 Answers1

1

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.

Tim
  • 92
  • 10
  • My question here is: Do I have to put the class to another file like in Java, or do I do it into the main? Providing the full code or the changes to my code would fix all my questions. Thanks – Skerdi Velo May 24 '23 at 12:28
  • You can do either. Copy paste to your main. Then call this last function somewhere. – Tim May 24 '23 at 14:32