EPG-Erinnerungen: Rechtsklick auf Sendung, Glocke-Indikator, MessageBox-Benachrichtigung

This commit is contained in:
administrator 2026-05-17 16:55:16 +02:00
parent faa852016d
commit 5bf1f06bfe
4 changed files with 175 additions and 0 deletions

View file

@ -19,6 +19,7 @@ public partial class MainWindow : Window
private Media? _currentMedia;
private AppSettings _settings = AppSettings.Load();
private readonly EpgService _epgService = new();
private readonly ReminderService _reminderService = new();
private readonly LogoService _logoService = new();
private readonly ObservableCollection<Channel> _allChannels = new();
@ -1050,6 +1051,64 @@ public partial class MainWindow : Window
PlayChannel(target);
};
// Rechtsklick: Kontextmenu mit Erinnern-Option
box.MouseRightButtonDown += (_, args) =>
{
args.Handled = true;
var hasReminder = _reminderService.HasReminder(ch.Name, ev.StartTime);
var menu = new ContextMenu();
var remind = new MenuItem
{
Header = hasReminder ? "\u23f0 Erinnerung entfernen" : "\u23f0 5 min vorher erinnern",
FontSize = 13
};
remind.Click += (_, _) =>
{
if (hasReminder)
{
var existing = _reminderService.Reminders
.FirstOrDefault(r => r.ChannelName == ch.Name && r.StartTime == ev.StartTime);
if (existing != null) _reminderService.Remove(existing.Id);
}
else
{
_reminderService.Add(new Reminder
{
ChannelName = ch.Name,
Title = ev.Title,
Description = ev.Description ?? "",
StartTime = ev.StartTime,
EndTime = ev.EndTime,
MinutesBefore = 5
});
}
// Grid neu bauen damit Indikator aktualisiert wird
_ = BuildEpgGridAsync();
};
menu.Items.Add(remind);
box.ContextMenu = menu;
menu.IsOpen = true;
};
// Erinnerungs-Indikator anzeigen wenn Erinnerung gesetzt
if (_reminderService.HasReminder(ch.Name, ev.StartTime))
{
var bell = new TextBlock
{
Text = "\u23f0",
FontSize = 11,
HorizontalAlignment = HorizontalAlignment.Right,
VerticalAlignment = VerticalAlignment.Top,
Margin = new Thickness(0, 3, 4, 0),
IsHitTestVisible = false
};
var overlay = new Grid();
overlay.Children.Add(content);
overlay.Children.Add(bell);
box.Child = overlay;
}
return box;
}

16
Models/Reminder.cs Normal file
View file

@ -0,0 +1,16 @@
namespace FritzTV.Models;
public class Reminder
{
public Guid Id { get; set; } = Guid.NewGuid();
public required string ChannelName { get; set; }
public required string Title { get; set; }
public string Description { get; set; } = "";
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public int MinutesBefore { get; set; } = 5;
public bool Fired { get; set; } = false;
/// <summary>Zeitpunkt zu dem die Benachrichtigung ausgelöst wird</summary>
public DateTime NotifyAt => StartTime.AddMinutes(-MinutesBefore);
}

View file

@ -36,4 +36,5 @@ public static class AppPaths
public static string Epg => Path.Combine(Root, "epg");
public static string CrashLog => Path.Combine(Root, "crash.log");
public static string WebView2Profile => Path.Combine(Root, "webview2");
public static string Reminders => Path.Combine(Root, "reminders.json");
}

View file

@ -0,0 +1,99 @@
using System.IO;
using System.Text.Json;
using System.Windows.Threading;
using FritzTV.Models;
namespace FritzTV.Services;
public class ReminderService
{
private static readonly string RemindersPath = AppPaths.Reminders;
private readonly DispatcherTimer _checkTimer;
private List<Reminder> _reminders = new();
/// <summary>Feuert wenn eine Erinnerung faellig ist. Callback laeuft auf UI-Thread.</summary>
public event Action<Reminder>? ReminderDue;
public IReadOnlyList<Reminder> Reminders => _reminders.AsReadOnly();
public ReminderService()
{
Load();
_checkTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(30) };
_checkTimer.Tick += (_, _) => CheckReminders();
_checkTimer.Start();
}
public void Add(Reminder reminder)
{
_reminders.Add(reminder);
Save();
}
public void Remove(Guid id)
{
_reminders.RemoveAll(r => r.Id == id);
Save();
}
public bool HasReminder(string channelName, DateTime startTime)
=> _reminders.Any(r => r.ChannelName == channelName && r.StartTime == startTime);
private void CheckReminders()
{
var now = DateTime.Now;
var due = _reminders
.Where(r => !r.Fired && r.NotifyAt <= now && r.StartTime > now.AddMinutes(-30))
.ToList();
foreach (var r in due)
{
r.Fired = true;
FireNotification(r);
ReminderDue?.Invoke(r);
}
_reminders.RemoveAll(r => r.Fired && r.StartTime < now.AddHours(-1));
if (due.Any()) Save();
}
private static void FireNotification(Reminder r)
{
try
{
var minLeft = (int)(r.StartTime - DateTime.Now).TotalMinutes;
var when = minLeft <= 0 ? "Jetzt" : $"In {minLeft} Minute{(minLeft == 1 ? "" : "n")}";
var msg = $"{when}: {r.Title}\n{r.ChannelName} {r.StartTime:HH:mm}\u2013{r.EndTime:HH:mm}";
System.Windows.MessageBox.Show(msg, "\u23f0 HomeStream-Erinnerung",
System.Windows.MessageBoxButton.OK,
System.Windows.MessageBoxImage.Information);
}
catch { }
}
private void Load()
{
try
{
if (File.Exists(RemindersPath))
{
var json = File.ReadAllText(RemindersPath);
_reminders = JsonSerializer.Deserialize<List<Reminder>>(json) ?? new();
_reminders.RemoveAll(r => r.StartTime < DateTime.Now.AddHours(-1));
}
}
catch { _reminders = new(); }
}
private void Save()
{
try
{
Directory.CreateDirectory(Path.GetDirectoryName(RemindersPath)!);
var json = JsonSerializer.Serialize(_reminders, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(RemindersPath, json);
}
catch { }
}
}