|
| 1 | +using System.Windows; |
| 2 | +using Bloxstrap.Models.RobloxApi; |
| 3 | +using Windows.UI.Notifications; |
| 4 | +using Windows.Data.Xml.Dom; |
| 5 | + |
| 6 | +namespace Bloxstrap.Integrations |
| 7 | +{ |
| 8 | + /// <summary> |
| 9 | + /// Service untuk menampilkan notifikasi Windows native untuk Roblox |
| 10 | + /// </summary> |
| 11 | + public class RobloxNotification : IDisposable |
| 12 | + { |
| 13 | + private const string LOG_IDENT = "RobloxNotification"; |
| 14 | + private const string APP_ID = "BoneFish"; |
| 15 | + |
| 16 | + private readonly ActivityWatcher _activityWatcher; |
| 17 | + private CancellationTokenSource? _notificationCheckToken; |
| 18 | + private Task? _notificationCheckTask; |
| 19 | + private HashSet<string> _notifiedUsers = new(); |
| 20 | + |
| 21 | + public event EventHandler<FriendNotificationEventArgs>? OnFriendOnline; |
| 22 | + public event EventHandler<NotificationEventArgs>? OnNotification; |
| 23 | + |
| 24 | + public RobloxNotification(ActivityWatcher activityWatcher) |
| 25 | + { |
| 26 | + _activityWatcher = activityWatcher; |
| 27 | + |
| 28 | + _activityWatcher.OnGameJoin += (_, _) => StartNotificationMonitoring(); |
| 29 | + _activityWatcher.OnGameLeave += (_, _) => StopNotificationMonitoring(); |
| 30 | + } |
| 31 | + |
| 32 | + public void StartNotificationMonitoring() |
| 33 | + { |
| 34 | + if (App.Settings.Prop.EnableRobloxNotifications == false) |
| 35 | + return; |
| 36 | + |
| 37 | + const string LOG_IDENT = "RobloxNotification"; |
| 38 | + App.Logger.WriteLine(LOG_IDENT, "Starting notification monitoring"); |
| 39 | + |
| 40 | + StopNotificationMonitoring(); |
| 41 | + |
| 42 | + _notificationCheckToken = new CancellationTokenSource(); |
| 43 | + _notifiedUsers.Clear(); |
| 44 | + |
| 45 | + _notificationCheckTask = Task.Run(async () => |
| 46 | + { |
| 47 | + while (!_notificationCheckToken.Token.IsCancellationRequested) |
| 48 | + { |
| 49 | + try |
| 50 | + { |
| 51 | + int delayMs = App.Settings.Prop.OptimizeForLowEnd ? 15000 : 5000; |
| 52 | + await Task.Delay(delayMs, _notificationCheckToken.Token); // Check interval configurable based on low-end optimization |
| 53 | + |
| 54 | + if (App.Settings.Prop.EnableFriendOnlineNotifications) |
| 55 | + { |
| 56 | + // Placeholder: Dalam implementasi nyata, ini akan mengambil data teman dari Roblox API |
| 57 | + // Untuk sekarang, ini adalah skeleton yang menunggu integrasi API |
| 58 | + await CheckFriendsStatus(); |
| 59 | + } |
| 60 | + } |
| 61 | + catch (OperationCanceledException) |
| 62 | + { |
| 63 | + break; |
| 64 | + } |
| 65 | + catch (Exception ex) |
| 66 | + { |
| 67 | + App.Logger.WriteLine(LOG_IDENT, $"Error in notification monitoring: {ex.Message}"); |
| 68 | + } |
| 69 | + } |
| 70 | + }, _notificationCheckToken.Token); |
| 71 | + } |
| 72 | + |
| 73 | + public void StopNotificationMonitoring() |
| 74 | + { |
| 75 | + if (_notificationCheckToken != null) |
| 76 | + { |
| 77 | + _notificationCheckToken.Cancel(); |
| 78 | + _notificationCheckToken.Dispose(); |
| 79 | + _notificationCheckToken = null; |
| 80 | + } |
| 81 | + |
| 82 | + _notifiedUsers.Clear(); |
| 83 | + } |
| 84 | + |
| 85 | + private async Task CheckFriendsStatus() |
| 86 | + { |
| 87 | + try |
| 88 | + { |
| 89 | + // TODO: Implementasi untuk mengambil status teman dari Roblox API |
| 90 | + // Untuk sekarang, ini adalah placeholder |
| 91 | + await Task.Delay(0); |
| 92 | + } |
| 93 | + catch (Exception ex) |
| 94 | + { |
| 95 | + App.Logger.WriteLine(LOG_IDENT, $"Error checking friends status: {ex.Message}"); |
| 96 | + } |
| 97 | + } |
| 98 | + |
| 99 | + public void ShowFriendOnlineNotification(string username) |
| 100 | + { |
| 101 | + try |
| 102 | + { |
| 103 | + if (_notifiedUsers.Contains(username)) |
| 104 | + return; |
| 105 | + |
| 106 | + _notifiedUsers.Add(username); |
| 107 | + |
| 108 | + // Buat XML untuk toast notification |
| 109 | + string toastXml = $@" |
| 110 | + <toast> |
| 111 | + <visual> |
| 112 | + <binding template='ToastText02'> |
| 113 | + <text id='1'>👋 {System.Net.WebUtility.HtmlEncode(username)} ada online!</text> |
| 114 | + <text id='2'>Apa mau main bareng?</text> |
| 115 | + </binding> |
| 116 | + </visual> |
| 117 | + <audio src='ms-winsoundevent:Notification.Default'/> |
| 118 | + </toast>"; |
| 119 | + |
| 120 | + var xmlDoc = new XmlDocument(); |
| 121 | + xmlDoc.LoadXml(toastXml); |
| 122 | + |
| 123 | + var toast = new ToastNotification(xmlDoc); |
| 124 | + toast.ExpirationTime = DateTime.Now.AddSeconds(30); |
| 125 | + |
| 126 | + try |
| 127 | + { |
| 128 | + ToastNotificationManager.CreateToastNotifier(APP_ID).Show(toast); |
| 129 | + } |
| 130 | + catch |
| 131 | + { |
| 132 | + // Fallback jika toast notifier tidak tersedia |
| 133 | + ShowGeneralNotification($"{username} ada online!", "Apa mau main bareng?"); |
| 134 | + } |
| 135 | + |
| 136 | + App.Logger.WriteLine(LOG_IDENT, $"Menampilkan notifikasi untuk teman online: {username}"); |
| 137 | + OnFriendOnline?.Invoke(this, new FriendNotificationEventArgs { Username = username }); |
| 138 | + } |
| 139 | + catch (Exception ex) |
| 140 | + { |
| 141 | + App.Logger.WriteLine(LOG_IDENT, $"Error showing friend notification: {ex.Message}"); |
| 142 | + } |
| 143 | + } |
| 144 | + |
| 145 | + public void ShowGeneralNotification(string title, string message) |
| 146 | + { |
| 147 | + try |
| 148 | + { |
| 149 | + // Buat XML untuk toast notification umum |
| 150 | + string toastXml = $@" |
| 151 | + <toast> |
| 152 | + <visual> |
| 153 | + <binding template='ToastText02'> |
| 154 | + <text id='1'>{System.Net.WebUtility.HtmlEncode(title)}</text> |
| 155 | + <text id='2'>{System.Net.WebUtility.HtmlEncode(message)}</text> |
| 156 | + </binding> |
| 157 | + </visual> |
| 158 | + <audio src='ms-winsoundevent:Notification.Default'/> |
| 159 | + </toast>"; |
| 160 | + |
| 161 | + var xmlDoc = new XmlDocument(); |
| 162 | + xmlDoc.LoadXml(toastXml); |
| 163 | + |
| 164 | + var toast = new ToastNotification(xmlDoc); |
| 165 | + toast.ExpirationTime = DateTime.Now.AddSeconds(15); |
| 166 | + |
| 167 | + try |
| 168 | + { |
| 169 | + ToastNotificationManager.CreateToastNotifier(APP_ID).Show(toast); |
| 170 | + } |
| 171 | + catch |
| 172 | + { |
| 173 | + // Fallback jika toast notifier tidak tersedia |
| 174 | + MessageBox.Show(message, title, MessageBoxButton.OK, MessageBoxImage.Information); |
| 175 | + } |
| 176 | + |
| 177 | + App.Logger.WriteLine(LOG_IDENT, $"Menampilkan notifikasi: {title}"); |
| 178 | + OnNotification?.Invoke(this, new NotificationEventArgs { Title = title, Message = message }); |
| 179 | + } |
| 180 | + catch (Exception ex) |
| 181 | + { |
| 182 | + App.Logger.WriteLine(LOG_IDENT, $"Error showing notification: {ex.Message}"); |
| 183 | + } |
| 184 | + } |
| 185 | + |
| 186 | + public void ResetFriendNotification(string username) |
| 187 | + { |
| 188 | + _notifiedUsers.Remove(username); |
| 189 | + } |
| 190 | + |
| 191 | + public void Dispose() |
| 192 | + { |
| 193 | + StopNotificationMonitoring(); |
| 194 | + } |
| 195 | + } |
| 196 | + |
| 197 | + public class FriendNotificationEventArgs : EventArgs |
| 198 | + { |
| 199 | + public string Username { get; set; } = ""; |
| 200 | + } |
| 201 | + |
| 202 | + public class NotificationEventArgs : EventArgs |
| 203 | + { |
| 204 | + public string Title { get; set; } = ""; |
| 205 | + public string Message { get; set; } = ""; |
| 206 | + } |
| 207 | +} |
0 commit comments