mirror of
https://github.com/friebetill/TubeCards.git
synced 2025-08-15 10:31:53 +08:00
177 lines
5.1 KiB
Dart
177 lines
5.1 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:built_collection/built_collection.dart';
|
|
import 'package:copy_with_extension/copy_with_extension.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:timezone/timezone.dart';
|
|
import 'package:uuid/uuid.dart';
|
|
|
|
import '../../modules/reminder/weekday.dart';
|
|
|
|
part 'reminder.g.dart';
|
|
|
|
/// The class stores a reminder for the user which is repeated weekly.
|
|
///
|
|
/// The weekly reminder always takes place at the same time, but can take
|
|
/// place on several days.
|
|
@CopyWith()
|
|
@immutable
|
|
class Reminder {
|
|
/// Returns an instance of [Reminder].
|
|
Reminder({
|
|
required this.weekdayStatus,
|
|
required this.timeOfDay,
|
|
required this.enabled,
|
|
int? id,
|
|
}) : id = id ?? const Uuid().v4().hashCode;
|
|
|
|
factory Reminder.initial() {
|
|
return Reminder(
|
|
enabled: true,
|
|
timeOfDay: TimeOfDay.now(),
|
|
weekdayStatus: BuiltMap({
|
|
Weekday.monday: true,
|
|
Weekday.tuesday: true,
|
|
Weekday.wednesday: true,
|
|
Weekday.thursday: true,
|
|
Weekday.friday: true,
|
|
Weekday.saturday: true,
|
|
Weekday.sunday: true,
|
|
}),
|
|
);
|
|
}
|
|
|
|
/// Converts the Json String into a Reminder object.
|
|
factory Reminder.fromJson(String jsonString) {
|
|
final parsed = jsonDecode(jsonString) as Map<String, dynamic>;
|
|
|
|
return Reminder(
|
|
id: parsed['id'] as int?,
|
|
enabled: parsed['enabled'] as bool?,
|
|
weekdayStatus: BuiltMap({
|
|
Weekday.monday: parsed['Monday'] as bool?,
|
|
Weekday.tuesday: parsed['Tuesday'] as bool?,
|
|
Weekday.wednesday: parsed['Wednesday'] as bool?,
|
|
Weekday.thursday: parsed['Thursday'] as bool?,
|
|
Weekday.friday: parsed['Friday'] as bool?,
|
|
Weekday.saturday: parsed['Saturday'] as bool?,
|
|
Weekday.sunday: parsed['Sunday'] as bool?,
|
|
}),
|
|
timeOfDay: TimeOfDay(
|
|
hour: parsed['hour'] as int,
|
|
minute: parsed['minute'] as int,
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Unique ID of the weekly reminder.
|
|
final int id;
|
|
|
|
/// Whether the reminder will fire at the specified weekday time.
|
|
final bool? enabled;
|
|
|
|
/// Day of the week.
|
|
final BuiltMap<Weekday, bool> weekdayStatus;
|
|
|
|
/// Time in the day, specifying hour and minute.
|
|
final TimeOfDay timeOfDay;
|
|
|
|
@override
|
|
bool operator ==(Object other) => other is Reminder && id == other.id;
|
|
|
|
@override
|
|
int get hashCode => id;
|
|
|
|
/// Converts the Reminder object into a json string.
|
|
String toJson() {
|
|
final map = {
|
|
'id': id,
|
|
'enabled': enabled,
|
|
'hour': timeOfDay.hour,
|
|
'minute': timeOfDay.minute,
|
|
Weekday.monday.toString(): weekdayStatus[Weekday.monday],
|
|
Weekday.tuesday.toString(): weekdayStatus[Weekday.tuesday],
|
|
Weekday.wednesday.toString(): weekdayStatus[Weekday.wednesday],
|
|
Weekday.thursday.toString(): weekdayStatus[Weekday.thursday],
|
|
Weekday.friday.toString(): weekdayStatus[Weekday.friday],
|
|
Weekday.saturday.toString(): weekdayStatus[Weekday.saturday],
|
|
Weekday.sunday.toString(): weekdayStatus[Weekday.sunday],
|
|
};
|
|
|
|
return jsonEncode(map);
|
|
}
|
|
|
|
/// Returns the configured hour of the weekly reminder.
|
|
int get hour {
|
|
return timeOfDay.hour;
|
|
}
|
|
|
|
/// Returns the configured minute of the weekly reminder.
|
|
int get minute {
|
|
return timeOfDay.minute;
|
|
}
|
|
|
|
/// Returns the time of the reminder as a formatted string, e.g. '12:00'.
|
|
String get time {
|
|
return '${_twoDigits(timeOfDay.hour)}:${_twoDigits(timeOfDay.minute)}';
|
|
}
|
|
|
|
String _twoDigits(int val) {
|
|
return val.toString().padLeft(2, '0');
|
|
}
|
|
|
|
Iterable<TZDateTime> getNextMatchingDateTimesStartingAt(
|
|
TZDateTime from,
|
|
) sync* {
|
|
if (!weekdayStatus.containsValue(true)) {
|
|
// No matching times since the reminder is disabled for each weekday.
|
|
return;
|
|
}
|
|
|
|
var nextMatchingDateTime = _getNextMatchingDateTimeStartingAt(from);
|
|
while (true) {
|
|
yield nextMatchingDateTime;
|
|
nextMatchingDateTime =
|
|
_getNextMatchingDateTimeStartingAt(nextMatchingDateTime);
|
|
}
|
|
}
|
|
|
|
/// Returns the next time where the time-based reminder would be triggered
|
|
/// assuming the card threshold is hit.
|
|
///
|
|
/// The reminder is triggered at a specific DateTime in case the weekday,
|
|
/// hour, and minute of the DateTime match with the values of the reminder.
|
|
///
|
|
/// In case the [from] time is already matching, the next matching time after
|
|
/// [from] is returned.
|
|
TZDateTime _getNextMatchingDateTimeStartingAt(TZDateTime from) {
|
|
final fromTimeWeekday = Weekday.fromInt(from.weekday);
|
|
|
|
// Check whether the next matching time is later on the given day.
|
|
if (weekdayStatus[fromTimeWeekday]! &&
|
|
(from.hour < timeOfDay.hour ||
|
|
(from.hour == timeOfDay.hour && from.minute < timeOfDay.minute))) {
|
|
return TZDateTime.local(
|
|
from.year,
|
|
from.month,
|
|
from.day,
|
|
timeOfDay.hour,
|
|
timeOfDay.minute,
|
|
);
|
|
}
|
|
|
|
var nextDate = from.add(const Duration(days: 1));
|
|
while (!weekdayStatus[Weekday.fromInt(nextDate.weekday)]!) {
|
|
nextDate = nextDate.add(const Duration(days: 1));
|
|
}
|
|
|
|
return TZDateTime.local(
|
|
nextDate.year,
|
|
nextDate.month,
|
|
nextDate.day,
|
|
timeOfDay.hour,
|
|
timeOfDay.minute,
|
|
);
|
|
}
|
|
}
|