protected override async Task ActuallyResetReminders(AccountDataItem account, AccountDataStore data) { try { // If reminders disabled, do nothing if (!account.RemindersDayBefore && !account.RemindersDayOf) { return; } await Task.Run(async delegate { // This gets called whenever changes are made in the account's data. AgendaViewItemsGroup agendaItems = await GetAgendaViewItemsGroup(account, DateTime.Now); // If no current semester, or no items, just clear all if (agendaItems == null || agendaItems.Items.Count == 0) { await RemoveAllNotificationsAsync(account.LocalAccountId); return; } DateTime now = DateTime.Now; await UpdateScheduledNotificationsAsync(account, agendaItems, now); }); } catch (Exception ex) { TelemetryExtension.Current?.TrackException(ex); } }
/// <summary> /// Guaranteed that data won't be null /// </summary> /// <param name="data"></param> /// <returns>Should always return an initialized list.</returns> private static async Task <List <BaseViewItemHomeworkExam> > getAllUpcomingBlocking(AccountDataItem account, AccountDataStore data, DateTime todayAsUtc, BaseUpcomingTileSettings tileSettings) { var currSemesterId = account.CurrentSemesterId; if (currSemesterId == Guid.Empty) { return(new List <BaseViewItemHomeworkExam>()); } ScheduleViewItemsGroup scheduleViewGroup; try { scheduleViewGroup = await ScheduleViewItemsGroup.LoadAsync(account.LocalAccountId, account.CurrentSemesterId, trackChanges : true, includeWeightCategories : false); } catch { // If semester not found return(new List <BaseViewItemHomeworkExam>()); } DateTime dateToStartDisplayingFrom = DateTime.SpecifyKind(tileSettings.GetDateToStartDisplayingOn(todayAsUtc), DateTimeKind.Utc); var agendaViewGroup = await AgendaViewItemsGroup.LoadAsync(account.LocalAccountId, scheduleViewGroup.Semester, DateTime.SpecifyKind(todayAsUtc, DateTimeKind.Local), trackChanges : true); // We're not going to worry about locking changes while we enumerate, since if collection changes while we're enumerating, there'll be a // new incoming reset request anyways // Agenda view group doesn't sort, so we have to sort it return(agendaViewGroup.Items.Where( i => i.Date.Date >= dateToStartDisplayingFrom && ((tileSettings.ShowHomework && i is ViewItemHomework) || (tileSettings.ShowExams && i is ViewItemExam)) ).OrderBy(i => i).ToList()); }
protected override async Task LoadAsyncOverride() { AgendaViewItemsGroup = await AgendaViewItemsGroup.LoadAsync(MainScreenViewModel.CurrentLocalAccountId, MainScreenViewModel.CurrentSemester, Today); AgendaViewItemsGroup.Items.CollectionChanged += new WeakEventHandler <NotifyCollectionChangedEventArgs>(Items_CollectionChanged).Handler; UpdateHasNoItems(); ListenToLocalEditsFor <DataLayer.DataItems.DataItemMegaItem>().ChangedItems += ItemsLocallyEditedListener_ChangedItems; }
private static async Task <AgendaViewItemsGroup> GetAgendaViewItemsGroup(AccountDataItem account, DateTime today) { try { // We're getting cached versions which might change as we're using the app, but that's fine, since if items change, another // ResetReminders will be incoming anyways var scheduleViewItemsGroup = await ScheduleViewItemsGroup.LoadAsync(account.LocalAccountId, account.CurrentSemesterId, trackChanges : true, includeWeightCategories : false); return(await AgendaViewItemsGroup.LoadAsync(account.LocalAccountId, scheduleViewItemsGroup.Semester, today, trackChanges : true)); } // If semester didn't exist, it throws null reference exception catch { return(null); } }
private async Task AddScheduledDayOfNotifications(AccountDataItem account, AgendaViewItemsGroup agendaItems, DateTime now) { try { DateTime today = now.Date; DateTime maxDate = today.AddDays(DAYS_IN_ADVANCE); BaseViewItemHomeworkExam[] itemsDueTodayOrGreater = agendaItems.Items.Where(i => i.Date.Date >= today && i.Date.Date <= maxDate).OrderBy(i => i).ToArray(); foreach (var item in itemsDueTodayOrGreater) { bool hasClassTime = false; DateTime reminderTime = GetDayOfReminderTime(item, out hasClassTime); if (!IsTimeOkay(reminderTime)) { continue; } string title = StringTools.TrimLengthWithEllipses(item.Name, 150); string subtitle = GetDueTimeAsString(item); string body = GetClassName(item); if (!string.IsNullOrWhiteSpace(item.Details)) { body += " - " + StringTools.TrimLengthWithEllipses(item.Details.Trim(), 200); } await ScheduleDayOfNotification(account.LocalAccountId, item, title, subtitle, body, reminderTime); } } catch (Exception ex) { TelemetryExtension.Current?.TrackException(ex); } }
public static DateTime GetDayBeforeReminderTime(DateTime date, AccountDataItem account, AgendaViewItemsGroup agenda) { DateTime?classEndTime = account.GetClassEndTime(date, agenda.Classes); if (classEndTime == null) { return(date.Date.AddHours(15)); // Default time is 3:00 PM } return(classEndTime.Value.AddMinutes(10)); // Otherwise 10 mins after the class end time }
public static void ScheduleDayBeforeAlarm(Context context, AccountDataItem account, DateTime today, AgendaViewItemsGroup agendaItems) { if (agendaItems == null) { return; } DateTime dayBeforeReminderTime = RemindersExtension.GetDayBeforeReminderTime(today, account, agendaItems); DateTime timeToScheduleAt; // If we haven't reached that time yet for "due tomorrow" if (dayBeforeReminderTime > DateTime.Now) { timeToScheduleAt = dayBeforeReminderTime.AddMilliseconds(1); } // Otherwise we'll need to set the timer for the "due today" else { timeToScheduleAt = today.AddDays(1).AddMilliseconds(1); } AlarmManagerHelper.Schedule( context: context, receiverType: typeof(UpdateDayBeforeNotificationReceiver), wakeTime: timeToScheduleAt, uriData: "powerplanner:?localAccountId=" + account.LocalAccountId, wakeDevice: true); }
private static async Task UpdateDayBeforeNotification(AccountDataItem account, AgendaViewItemsGroup agendaItems, Context context, NotificationManager notificationManager, bool fromForeground) { string tag = account.LocalAccountId.ToString(); // If no current semester, or no items, then just clear if (agendaItems == null || agendaItems.Items.Count == 0) { notificationManager.Cancel(tag, NotificationIds.DAY_BEFORE_NOTIFICATION); return; } StatusBarNotification existing; if (Android.OS.Build.VERSION.SdkInt >= BuildVersionCodes.M) { existing = notificationManager.GetActiveNotifications().FirstOrDefault(i => i.Id == NotificationIds.DAY_BEFORE_NOTIFICATION && i.Tag == tag); } else { // GetActiveNotifications didn't exist till API 23 existing = null; } const string EXTRA_UNIQUE_ID = "UniqueId"; DateTime now = DateTime.Now; DateTime reminderTime = RemindersExtension.GetDayBeforeReminderTime(now.Date, account, agendaItems); bool sendingDueTomorrow = now >= reminderTime; NotificationCompat.Builder builder; if (sendingDueTomorrow) { var itemsDueTomorrow = agendaItems.Items.Where(i => i.Date.Date == now.Date.AddDays(1)).OrderBy(i => i).ToArray(); // If nothing tomorrow, we clear if (itemsDueTomorrow.Length == 0) { notificationManager.Cancel(tag, NotificationIds.DAY_BEFORE_NOTIFICATION); return; } string extraUniqueId = "DueTomorrow" + string.Join(";", itemsDueTomorrow.Select(i => i.Name)).GetHashCode(); // If already updated if (existing != null && existing.Notification.Extras.GetString(EXTRA_UNIQUE_ID).Equals(extraUniqueId)) { return; } // If all the items have been updated more recently than the reminder time, we won't show a new notification if (existing == null && itemsDueTomorrow.All(i => i.Updated.ToLocalTime() > reminderTime)) { return; } // If we already sent the notification today if (account.DateLastDayBeforeReminderWasSent.Date == now.Date) { // If the notification has been dismissed, do nothing if (existing == null) { return; } } // Otherwise we need to update the date that it was sent else { account.DateLastDayBeforeReminderWasSent = now; await AccountsManager.Save(account); } if (existing == null && fromForeground) { return; } builder = CreateReminderBuilderForDayBefore(context, account.LocalAccountId); Bundle b = new Bundle(); b.PutString(EXTRA_UNIQUE_ID, extraUniqueId); builder.SetExtras(b); // "Due tomorrow" builder.SetContentTitle(PowerPlannerResources.GetDueX(PowerPlannerResources.GetRelativeDateTomorrow().ToLower())); PopulateNotificationDayBeforeWithItems(builder, itemsDueTomorrow); } // Otherwise "due today" else { var itemsDueToday = agendaItems.Items.Where(i => i.Date.Date == now.Date).OrderBy(i => i).ToArray(); // If nothing left today, we clear if (itemsDueToday.Length == 0) { notificationManager.Cancel(tag, NotificationIds.DAY_BEFORE_NOTIFICATION); return; } string extraUniqueId = "DueToday" + string.Join(";", itemsDueToday.Select(i => i.Name)).GetHashCode(); // If already updated if (existing != null && existing.Notification.Extras.GetString(EXTRA_UNIQUE_ID).Equals(extraUniqueId)) { return; } // If the notification doesn't currently exist (user potentially dismissed it) and we've already sent either yesterday or today if (existing == null && account.DateLastDayBeforeReminderWasSent.Date == DateTime.Today.AddDays(-1) || account.DateLastDayBeforeReminderWasSent.Date == DateTime.Today) { return; } // If all the items have been updated more recently than the reminder time, we won't show a new notification if (existing == null && itemsDueToday.All(i => i.Updated.ToLocalTime() > reminderTime)) { return; } // If we already sent the notification yesterday if (account.DateLastDayBeforeReminderWasSent.Date == now.Date.AddDays(-1)) { // If the notification has been dismissed, do nothing if (existing == null) { return; } } // Otherwise we need to update the date that it was sent else { account.DateLastDayBeforeReminderWasSent = now.Date.AddDays(-1); await AccountsManager.Save(account); } if (existing == null && fromForeground) { return; } builder = CreateReminderBuilderForDayBefore(context, account.LocalAccountId); Bundle b = new Bundle(); b.PutString(EXTRA_UNIQUE_ID, extraUniqueId); builder.SetExtras(b); // "Due today" builder.SetContentTitle(PowerPlannerResources.GetDueX(PowerPlannerResources.GetRelativeDateToday().ToLower())); PopulateNotificationDayBeforeWithItems(builder, itemsDueToday); } notificationManager.Notify(tag, NotificationIds.DAY_BEFORE_NOTIFICATION, BuildReminder(builder)); }
/// <summary> /// Returns a list of items that should have active notifications (ignoring whether user already dismissed them) /// </summary> /// <param name="account"></param> /// <param name="agendaItems"></param> /// <param name="now"></param> /// <param name="nextReminderTime"></param> /// <returns></returns> private static List <Tuple <BaseViewItemHomeworkExam, DateTime> > GetItemsThatCouldHaveDayOfNotifications(AccountDataItem account, AgendaViewItemsGroup agendaItems, DateTime now, out DateTime nextReminderTime) { List <Tuple <BaseViewItemHomeworkExam, DateTime> > shouldBeActive = new List <Tuple <BaseViewItemHomeworkExam, DateTime> >(); nextReminderTime = DateTime.MinValue; PowerPlannerSending.Schedule.Week currentWeek = account.GetWeekOnDifferentDate(now); // Add past-due incomplete tasks (we don't add exams since they're "complete" when they're past-due) foreach (var task in agendaItems.Items.OfType <ViewItemHomework>().Where(i => i.Date.Date < now.Date).OrderBy(i => i)) { shouldBeActive.Add(new Tuple <BaseViewItemHomeworkExam, DateTime>(task, task.Date.Date)); } // Look at items due today // NOTE: Assuming that end time is always on the same day. If we allow events that span multiple days, // we might need to update this so it correctly expires the event on the future date. // To make sure we include items due 00:30 on the next day, we have to factor in tomorrow DateTime tomorrow = now.Date.AddDays(1); var weekForTomorrow = account.GetWeekOnDifferentDate(tomorrow); foreach (var item in agendaItems.Items.Where(i => i.Date.Date == now.Date || i.Date.Date == tomorrow).OrderBy(i => i)) { // Get the reminder time DateTime reminderTime = GetDayOfReminderTime(item.Date.Date == tomorrow ? weekForTomorrow : currentWeek, item); // If it's past the reminder time if (now >= reminderTime) { // If it has an end time DateTime endTime; if (item.TryGetEndDateWithTime(out endTime)) { // We have to consider the end time for updating reminders, since events // expire once they're over (so need to update again right when an event completes) if (endTime > now && (nextReminderTime == DateTime.MinValue || endTime < nextReminderTime)) { shouldBeActive.Add(new Tuple <BaseViewItemHomeworkExam, DateTime>(item, reminderTime)); nextReminderTime = endTime; } } else { // Otherwise add it shouldBeActive.Add(new Tuple <BaseViewItemHomeworkExam, DateTime>(item, reminderTime)); } } else if (nextReminderTime == DateTime.MinValue || reminderTime < nextReminderTime) { nextReminderTime = reminderTime; } } // If no time found, we pick an item that's due in the future if (nextReminderTime == DateTime.MinValue) { DateTime?nextDateWithItems = agendaItems.Items.Where(i => i.Date.Date > now.Date).OrderBy(i => i.Date.Date).FirstOrDefault()?.Date.Date; if (nextDateWithItems != null) { // Get the week for that date var week = account.GetWeekOnDifferentDate(nextDateWithItems.Value); // Look through all items on that date foreach (var item in agendaItems.Items.Where(i => i.Date.Date == nextDateWithItems.Value)) { // Pick the smallest reminder time DateTime reminderTime = GetDayOfReminderTime(currentWeek, item); if (nextReminderTime == DateTime.MinValue || reminderTime < nextReminderTime) { nextReminderTime = reminderTime; } } } } return(shouldBeActive); }
private static async Task UpdateAndScheduleDayOfNotifications(AccountDataItem account, AgendaViewItemsGroup agendaItems, Context context, NotificationManager notificationManager, DateTime now, bool fromForeground) { string tagForAccountStartsWith = account.LocalAccountId.ToString(); List <StatusBarNotification> existingNotifs; if (Android.OS.Build.VERSION.SdkInt >= BuildVersionCodes.M) { existingNotifs = notificationManager.GetActiveNotifications().Where(i => i.Id == NotificationIds.DAY_OF_NOTIFICATIONS && i.Tag != null && i.Tag.StartsWith(tagForAccountStartsWith)).ToList(); } else { // GetActiveNotifications didn't exist before version 23 existingNotifs = new List <StatusBarNotification>(); } // If no current semester, or no items, then just clear if (agendaItems == null || agendaItems.Items.Count == 0) { foreach (var notif in existingNotifs) { notificationManager.Cancel(notif.Tag, NotificationIds.DAY_OF_NOTIFICATIONS); } return; } DateTime nextReminderTime; var itemsThatCouldHaveNotifs = GetItemsThatCouldHaveDayOfNotifications(account, agendaItems, now, out nextReminderTime); // Remove ones that don't exist anymore for (int i = 0; i < existingNotifs.Count; i++) { var existing = existingNotifs[i]; Guid identifier; if (TryGetItemIdFromDayOfTag(existing.Tag, out identifier)) { if (!itemsThatCouldHaveNotifs.Any(x => x.Item1.Identifier == identifier)) { notificationManager.Cancel(existing.Tag, NotificationIds.DAY_OF_NOTIFICATIONS); existingNotifs.RemoveAt(i); i--; } } } foreach (var item in itemsThatCouldHaveNotifs) { UpdateDayOfNotification(account.LocalAccountId, item.Item1, item.Item2, context, notificationManager, existingNotifs, fromForeground); } // Need to mark them as sent Guid[] newlySentHomeworkReminders = itemsThatCouldHaveNotifs.Select(i => i.Item1).OfType <ViewItemHomework>().Where(i => !i.HasSentReminder).Select(i => i.Identifier).ToArray(); Guid[] newlySentExamReminders = itemsThatCouldHaveNotifs.Select(i => i.Item1).OfType <ViewItemExam>().Where(i => !i.HasSentReminder).Select(i => i.Identifier).ToArray(); if (newlySentHomeworkReminders.Length > 0 || newlySentExamReminders.Length > 0) { var dataStore = await AccountDataStore.Get(account.LocalAccountId); if (dataStore != null) { await dataStore.MarkAndroidRemindersSent(newlySentHomeworkReminders, newlySentExamReminders); } } // Schedule the next alarm if (nextReminderTime > now) { AlarmManagerHelper.Schedule( context: context, receiverType: typeof(UpdateDayOfNotificationsReceiver), wakeTime: nextReminderTime, uriData: "powerplanner:?localAccountId=" + account.LocalAccountId, wakeDevice: true); } }
private static async Task UpdateAndScheduleDayBeforeNotification(Context context, AccountDataItem account, AgendaViewItemsGroup agendaItems, NotificationManager notificationManager, DateTime now, bool fromForeground) { // Update the day before notification await UpdateDayBeforeNotification(account, agendaItems, context, notificationManager, fromForeground); // And then schedule the next alarm ScheduleDayBeforeAlarm(context, account, now.Date, agendaItems); }
private async Task AddScheduledDayBeforeNotifications(AccountDataItem account, AgendaViewItemsGroup agendaItems, DateTime now) { try { string idStartString = GetIdentifierStartStringForDayBefore(account.LocalAccountId); DateTime artificialToday = now.Date; for (int i = 0; i < DAYS_IN_ADVANCE; i++, artificialToday = artificialToday.AddDays(1)) { DateTime artificialTomorrow = artificialToday.AddDays(1); BaseViewItemHomeworkExam[] itemsOnDay = agendaItems.Items.Where(x => x.Date.Date == artificialTomorrow).OrderBy(x => x).ToArray(); if (itemsOnDay.Length > 0) { DateTime reminderTime = RemindersExtension.GetDayBeforeReminderTime(artificialToday, account, agendaItems); string title = "Due tomorrow"; string body = ""; if (itemsOnDay.Length == 1) { body = StringTools.TrimLengthWithEllipses(itemsOnDay[0].Name, 200); } else { title += " (" + itemsOnDay.Length + ")"; foreach (var item in itemsOnDay.Take(5)) { body += StringTools.TrimLengthWithEllipses(item.Name, 30) + "\n"; } body = body.Trim(); } await ScheduleDayBeforeNotification(idStartString + artificialToday.ToString(DAY_BEFORE_DATE_FORMAT, CultureInfo.InvariantCulture), title, body, reminderTime); } } } catch (Exception ex) { TelemetryExtension.Current?.TrackException(ex); } }
private async Task UpdateScheduledNotificationsAsync(AccountDataItem account, AgendaViewItemsGroup agendaItems, DateTime now) { // Just remove all, we would be overwriting them anyways await RemoveAllScheduledNotificationsAsync(account.LocalAccountId); await AddScheduledDayBeforeNotifications(account, agendaItems, now); await AddScheduledDayOfNotifications(account, agendaItems, now); }
private async Task ResetReminders(AccountDataItem account, CancellationToken token) { if (account == null) { return; } ClearReminders(account.LocalAccountId, token); token.ThrowIfCancellationRequested(); var semesterId = account.CurrentSemesterId; if (semesterId == Guid.Empty) { return; } DateTime todayAsUtc = DateTime.SpecifyKind(DateTime.Today, DateTimeKind.Utc); ViewItemTaskOrEvent[] itemsDueTodayOrGreater; ViewItemSchedule[] allSchedules; try { ScheduleViewItemsGroup viewModelSchedule = await ScheduleViewItemsGroup.LoadAsync(account.LocalAccountId, semesterId, trackChanges : true, includeWeightCategories : false); AgendaViewItemsGroup viewModel = await AgendaViewItemsGroup.LoadAsync(account.LocalAccountId, viewModelSchedule.Semester, DateTime.SpecifyKind(todayAsUtc, DateTimeKind.Local), trackChanges : true); // Data we need to load and hold are... // - Items due today or greater // - All schedules // We don't need to worry about holding a lock though, if the collections change and that breaks us, that's fine, // that implies that the data has been changed anyways and another ResetReminders will come in. // Therefore we should also expect to get some exceptions here. allSchedules = viewModelSchedule.Classes.SelectMany(i => i.Schedules).ToArray(); itemsDueTodayOrGreater = viewModel.Items.Where(i => i.Date.Date >= DateTime.SpecifyKind(todayAsUtc, DateTimeKind.Local)).ToArray(); } catch { // Semester wasn't found or other misc error return; } // Since we're no longer inside the lock and we're using a view group that tracks changes, any properties we access on the view items could change at any time. // Therefore we need to take that into consideration and be careful about what we do. if (account.RemindersDayBefore) { Dictionary <DateTime, List <ViewItemTaskOrEvent> > groupedByDay = new Dictionary <DateTime, List <ViewItemTaskOrEvent> >(); DateTime tomorrow = DateTime.SpecifyKind(todayAsUtc.AddDays(1), DateTimeKind.Local); //select all incomplete tasks/events that is due on tomorrow or later foreach (ViewItemTaskOrEvent h in itemsDueTodayOrGreater.Where(i => i.Date.Date >= tomorrow)) { token.ThrowIfCancellationRequested(); var hDate = h.Date.Date; if (!groupedByDay.TryGetValue(hDate, out List <ViewItemTaskOrEvent> group)) { group = new List <ViewItemTaskOrEvent>(); groupedByDay[hDate] = group; } group.Add(h); } foreach (var pair in groupedByDay) { token.ThrowIfCancellationRequested(); DateTime dueOn = pair.Key; List <ViewItemTaskOrEvent> items = pair.Value; DateTime reminderTime = GetDayBeforeReminderTime(dueOn.AddDays(-1), account, allSchedules); if (!IsTimeOkay(reminderTime)) { continue; } ViewItemTaskOrEvent[] tasks = items.Where(i => i.Type == TaskOrEventType.Task).ToArray(); ViewItemTaskOrEvent[] events = items.Where(i => i.Type == TaskOrEventType.Event).ToArray(); if (tasks.Length > 0) { XmlDocument xml = GenerateToastReminder( tasks.Length == 1 ? "You have 1 item due tomorrow" : "You have " + tasks.Length + " items due tomorrow", GetItemLineText(tasks[0]), tasks.Length >= 2 ? GetItemLineText(tasks[1]) : null, #pragma warning disable 0612 new QueryStringHelper() #pragma warning restore 0612 .SetLocalAccountId(account.LocalAccountId) .SetAction("DayBeforeHomeworkReminder") .ToString() ); string remoteId = null; if (account.IsOnlineAccount) { int hashedItems = string.Join(";", tasks.Select(i => i.Identifier)).GetHashCode(); remoteId = $"PP_DayBeforeHomeworks_{account.AccountId}_{hashedItems}"; } Schedule( GenerateScheduledToastNotification( xml, reminderTime, GetId(account), //id's don't need to be unique remoteId) ); } if (events.Length > 0) { XmlDocument xml = GenerateToastReminder( events.Length == 1 ? "You have 1 event tomorrow" : "You have " + events.Length + " events tomorrow", GetItemLineText(events[0]), events.Length >= 2 ? GetItemLineText(events[1]) : null, #pragma warning disable 0612 new QueryStringHelper() #pragma warning restore 0612 .SetLocalAccountId(account.LocalAccountId) .SetAction("DayBeforeExamReminder") .ToString() ); string remoteId = null; if (account.IsOnlineAccount) { int hashedItems = string.Join(";", events.Select(i => i.Identifier)).GetHashCode(); remoteId = $"PP_DayBeforeExams_{account.AccountId}_{hashedItems}"; } Schedule( GenerateScheduledToastNotification( xml, reminderTime, GetId(account), remoteId)); } } } if (account.RemindersDayOf) { foreach (ViewItemTaskOrEvent h in itemsDueTodayOrGreater) { token.ThrowIfCancellationRequested(); bool hasClassTime = false; DateTime reminderTime = GetDayOfReminderTime(h, ref hasClassTime); if (!IsTimeOkay(reminderTime)) { continue; } string subtitle = GetClassName(h) + " - "; if (h.Type == TaskOrEventType.Task) { subtitle += "due "; } if (hasClassTime) { subtitle += "in one hour"; } else { subtitle += "today"; } XmlDocument xml = GenerateToastReminder( TrimString(h.Name, 200), subtitle, TrimString(h.Details, 200), ArgumentsHelper.CreateArgumentsForView(h, account.LocalAccountId).SerializeToString() ); string remoteId = null; if (account.IsOnlineAccount) { remoteId = $"PP_DayOf_{account.AccountId}_{h.Identifier}"; } Schedule( GenerateScheduledToastNotification( xml, reminderTime, GetId(account), remoteId)); } } }
private async System.Threading.Tasks.Task InitializeDataAsync() { List <object> items = null; List <BaseViewItemHomeworkExam> tasks = null; _now = DateTime.Now; bool hasAccount = false; bool isDisabledInSettings = false; bool hasSemester = false; try { await System.Threading.Tasks.Task.Run(async delegate { var account = await AccountsManager.GetLastLogin(); AccountDataStore data = null; if (account != null) { data = await AccountDataStore.Get(account.LocalAccountId); } if (data != null) { hasAccount = true; isDisabledInSettings = account.MainTileSettings.IsDisabled(); if (!isDisabledInSettings) { _localAccountId = account.LocalAccountId; var currSemesterId = account.CurrentSemesterId; if (currSemesterId != Guid.Empty) { ScheduleViewItemsGroup scheduleViewGroup; try { scheduleViewGroup = await ScheduleViewItemsGroup.LoadAsync(account.LocalAccountId, account.CurrentSemesterId, trackChanges: true, includeWeightCategories: false); } catch { // If semester not found scheduleViewGroup = null; } if (scheduleViewGroup != null) { DateTime dateToStartDisplayingFrom = DateTime.SpecifyKind(account.MainTileSettings.GetDateToStartDisplayingOn(_now.Date), DateTimeKind.Utc); // We don't track changes since we need a fresh version that has been filtered right now. // Otherwise when we update for an event expiring, if we have a cached version, that event wouldn't have expired! var agendaViewGroup = await AgendaViewItemsGroup.LoadAsync(account.LocalAccountId, scheduleViewGroup.Semester, _now.Date, trackChanges: false); hasSemester = true; // We lock the outside, since we are allowing trackChanges on the view items groups (so we have a chance of loading a cached one)... and since we're on a background thread, the lists inside the // view items groups could change while we're enumerating, hence throwing an exception. So we lock it to ensure this won't happen, and then we return a copy of the items that we need. using (await agendaViewGroup.DataChangeLock.LockForReadAsync()) { var filtered = agendaViewGroup.Items .Where(i => i.Date.Date >= dateToStartDisplayingFrom); if (!account.MainTileSettings.ShowHomework) { filtered = filtered.Where(i => !(i is ViewItemHomework)); } if (!account.MainTileSettings.ShowExams) { filtered = filtered.Where(i => !(i is ViewItemExam)); } // Agenda view group doesn't sort, so we have to sort it tasks = filtered .OrderBy(i => i) .Take(20) .ToList(); // Add date headers items = new List <object>(); DateTime lastHeader = DateTime.MinValue; foreach (var t in tasks) { if (lastHeader != t.Date.Date) { items.Add(t.Date.Date); lastHeader = t.Date.Date; } items.Add(t); } } } } } } }); if (items == null || items.Count == 0) { if (hasSemester) { items = new List <object>() { PowerPlannerResources.GetString("String_NothingDue") }; } else if (isDisabledInSettings) { items = new List <object>() { PowerPlannerResources.GetString("String_WidgetDisabled") }; } else if (hasAccount) { items = new List <object>() { PowerPlannerResources.GetString("String_NoSemester") }; } else { items = new List <object>() { PowerPlannerResources.GetString("String_NoAccount") }; } } _items = items; } catch (Exception ex) { TelemetryExtension.Current?.TrackException(ex); } // Schedule next try { if (tasks != null && tasks.Count > 0) { DateTime?nextChangeTime = GetNextAgendaChangeTime(tasks, _now); if (nextChangeTime != null) { AlarmManagerHelper.Schedule( context: _context, receiverType: typeof(UpdateWidgetAgendaReceiver), wakeTime: nextChangeTime.Value); } } } catch (Exception ex) { TelemetryExtension.Current?.TrackException(ex); } }