/// <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()); }
private async Task OnSemesterChanged() { // Restore the default stored items NavigationManager.RestoreDefaultMemoryItems(); // Disconnect the previous if (ScheduleViewItemsGroup != null) { Classes.EndMakeThisACopyOf(ScheduleViewItemsGroup.Classes); if (_scheduleChangesOccurredHandler != null) { ScheduleViewItemsGroup.OnChangesOccurred -= _scheduleChangesOccurredHandler; } ScheduleViewItemsGroup = null; } // Clear the current classes Classes.Clear(); // If there's believed to be a semester (although that semester may not exist, this simply means Guid isn't empty) if (!hasNoSemester()) { // Load the classes/schedules try { ScheduleViewItemsGroup = await ScheduleViewItemsGroup.LoadAsync(this.CurrentLocalAccountId, this.CurrentSemesterId); } catch (SemesterNotFoundException) { // Semester didn't actually exist CurrentSemesterId = Guid.Empty; return; } // Change the default date // If semester has already ended if (!PowerPlannerSending.DateValues.IsUnassigned(CurrentSemester.End) && DateTime.SpecifyKind(CurrentSemester.End, DateTimeKind.Local).Date < DateTime.Today) { NavigationManager.SetDisplayMonth(DateTime.SpecifyKind(CurrentSemester.End, DateTimeKind.Local), preserveForever: true); NavigationManager.SetSelectedDate(DateTime.SpecifyKind(CurrentSemester.End, DateTimeKind.Local), preserveForever: true); } // If semester hasn't started yet else if (!PowerPlannerSending.DateValues.IsUnassigned(CurrentSemester.Start) && DateTime.SpecifyKind(CurrentSemester.Start, DateTimeKind.Local).Date > DateTime.Today) { NavigationManager.SetDisplayMonth(DateTime.SpecifyKind(CurrentSemester.Start, DateTimeKind.Local), preserveForever: true); NavigationManager.SetSelectedDate(DateTime.SpecifyKind(CurrentSemester.Start, DateTimeKind.Local), preserveForever: true); } // Make this a copy of the Classes list Classes.MakeThisACopyOf(ScheduleViewItemsGroup.Classes); if (_scheduleChangesOccurredHandler == null) { _scheduleChangesOccurredHandler = new WeakEventHandler <DataChangedEvent>(ViewModelSchedule_OnChangesOccurred).Handler; } ScheduleViewItemsGroup.OnChangesOccurred += _scheduleChangesOccurredHandler; } }
public Task ResetAllRemindersAsync(AccountDataItem account) { // If they weren't enabled, we won't do anything. The only time they get disabled is from settings, and we'll clear when that happens. if (!account.AreClassRemindersEnabled()) { return(Task.CompletedTask); } return(_workQueue.QueueOrMergeAsync(account.LocalAccountId, () => Task.Run(async delegate { try { ScheduleViewItemsGroup scheduleViewItemsGroup = null; var currSemesterId = account.CurrentSemesterId; if (currSemesterId != Guid.Empty && account.AreClassRemindersEnabled()) { // 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. scheduleViewItemsGroup = await ScheduleViewItemsGroup.LoadAsync(account.LocalAccountId, currSemesterId, trackChanges: false, includeWeightCategories: false); } ResetAllReminders(account, scheduleViewItemsGroup); } catch (Exception ex) { TelemetryExtension.Current?.TrackException(ex); } }))); }
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 static async Task <ClassData> LoadDataBlocking(AccountDataStore data, Guid classId, DateTime todayAsUtc, ClassTileSettings settings) { DateTime dateToStartDisplayingFrom = DateTime.SpecifyKind(settings.GetDateToStartDisplayingOn(todayAsUtc), DateTimeKind.Local); Guid semesterId = Guid.Empty; // 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 Locks.LockDataForReadAsync()) { // First we need to obtain the semester id var c = data.TableClasses.FirstOrDefault(i => i.Identifier == classId); if (c == null) { return(null); } semesterId = c.UpperIdentifier; } // We need all classes loaded, to know what time the end of day is var scheduleViewItemsGroup = await ScheduleViewItemsGroup.LoadAsync(data.LocalAccountId, semesterId, trackChanges : true, includeWeightCategories : false); var classViewItemsGroup = await ClassViewItemsGroup.LoadAsync( localAccountId : data.LocalAccountId, classId : classId, today : DateTime.SpecifyKind(todayAsUtc, DateTimeKind.Local), viewItemSemester : scheduleViewItemsGroup.Semester, includeWeights : false); classViewItemsGroup.LoadTasksAndEvents(); await classViewItemsGroup.LoadTasksAndEventsTask; List <ViewItemTaskOrEvent> copied; using (await classViewItemsGroup.DataChangeLock.LockForReadAsync()) { // Class view group sorts the items, so no need to sort copied = classViewItemsGroup.Class.TasksAndEvents.Where(i => i.Date.Date >= dateToStartDisplayingFrom).ToList(); } return(new ClassData() { Class = classViewItemsGroup.Class, AllUpcoming = copied }); }
protected override async Task LoadAsyncOverride() { await base.LoadAsyncOverride(); if (Account.CurrentSemesterId == Guid.Empty) { return; } try { var viewItems = await ScheduleViewItemsGroup.LoadAsync(Account.LocalAccountId, Account.CurrentSemesterId, trackChanges : true, includeWeightCategories : false); HasSemester = true; // We lock since we're tracking changes, and can't let the list change while enumerating it initially using (await viewItems.DataChangeLock.LockForReadAsync()) { if (viewItems.Classes.Count == 0) { return; } HasClasses = true; var classes = new List <ClassAndPinnedStatus>(); foreach (var c in viewItems.Classes) { classes.Add(new ClassAndPinnedStatus() { Class = c, IsPinned = ClassTileHelper.IsPinned(Account.LocalAccountId, c.Identifier) }); } Classes = classes; } } catch (SemesterNotFoundException) { } }
/// <summary> /// /// </summary> /// <param name="account"></param> /// <param name="today">As local time</param> /// <param name="daysIncludingToday"></param> /// <returns></returns> public static async Task <ScheduleTileDataHelper> LoadAsync(AccountDataItem account, DateTime today, int daysIncludingToday) { var answer = new ScheduleTileDataHelper() { Account = account, DaysIncludingToday = daysIncludingToday, Today = today.Date }; var currSemesterId = account.CurrentSemesterId; if (currSemesterId != Guid.Empty) { try { answer.ScheduleViewItemsGroup = await ScheduleViewItemsGroup.LoadAsync(account.LocalAccountId, currSemesterId, trackChanges : true, includeWeightCategories : false); answer.HasSemester = true; } catch { // If semester not found return(answer); } try { answer.HolidayViewItemsGroup = await HolidayViewItemsGroup.LoadAsync(account.LocalAccountId, answer.ScheduleViewItemsGroup.Semester, today, today.AddDays(daysIncludingToday - 1), trackChanges : false); } catch (Exception ex) { TelemetryExtension.Current?.TrackException(ex); } } // TODO: Genericize the logic between UWP and Android return(answer); }
public static DayScheduleItemsArranger Create(AccountDataItem account, SemesterItemsViewGroup semesterItems, ScheduleViewItemsGroup scheduleGroup, DateTime date, double heightOfHour, double spacingWhenNoAdditionalItems, double spacingWithAdditionalItems, double widthOfCollapsed, bool includeHomeworkAndHolidays) { if (account == null) { throw new ArgumentNullException(nameof(account)); } if (semesterItems == null) { throw new ArgumentNullException(nameof(semesterItems)); } if (scheduleGroup == null) { throw new ArgumentNullException(nameof(scheduleGroup)); } date = date.Date; foreach (var cachedAnswer in _cached) { if (cachedAnswer.Date == date.Date && cachedAnswer._semesterItems == semesterItems && cachedAnswer.HeightOfHour == heightOfHour && cachedAnswer._spacingWhenNoAdditionalItems == spacingWhenNoAdditionalItems && cachedAnswer._spacingWithAdditionalItems == spacingWithAdditionalItems && cachedAnswer._widthOfCollapsed == widthOfCollapsed) { return(cachedAnswer); } } DayScheduleItemsArranger answer = new DayScheduleItemsArranger(account, semesterItems, scheduleGroup, date, heightOfHour, spacingWhenNoAdditionalItems, spacingWithAdditionalItems, widthOfCollapsed, includeHomeworkAndHolidays); _cached.Add(answer); return(answer); }
private DayScheduleItemsArranger(AccountDataItem account, SemesterItemsViewGroup semesterItems, ScheduleViewItemsGroup scheduleGroup, DateTime date, double heightOfHour, double spacingWhenNoAdditionalItems, double spacingWithAdditionalItems, double widthOfCollapsed, bool includeHomeworkAndHolidays) { if (semesterItems.Semester == null) { throw new NullReferenceException("Semester was null"); } _semesterItems = semesterItems; semesterItems.OnItemsChanged += new WeakEventHandler <EventArgs>(SemesterGroup_OnItemsChanged).Handler; scheduleGroup.OnChangesOccurred += new WeakEventHandler <DataChangedEvent>(ScheduleViewItemsGroup_OnChangesOccurred).Handler; Date = date; _spacingWhenNoAdditionalItems = spacingWhenNoAdditionalItems; _spacingWithAdditionalItems = spacingWithAdditionalItems; _widthOfCollapsed = widthOfCollapsed; Account = account; HeightOfHour = heightOfHour; MinDuration = TimeSpan.FromHours(widthOfCollapsed / HeightOfHour); IsDifferentSemester = !semesterItems.Semester.IsDateDuringThisSemester(date); SchedulesOnDay schedules = null; if (!IsDifferentSemester) { schedules = SchedulesOnDay.Get(semesterItems.Classes, date, account.GetWeekOnDifferentDate(date), trackChanges: true); schedules.CollectionChanged += new WeakEventHandler <NotifyCollectionChangedEventArgs>(Schedules_CollectionChanged).Handler; } _schedules = schedules; if (includeHomeworkAndHolidays) { _events = HomeworksOnDay.Get(semesterItems.Items, date); _events.CollectionChanged += new WeakEventHandler <NotifyCollectionChangedEventArgs>(Events_CollectionChanged).Handler; } else { _events = new MyObservableList <BaseViewItemHomeworkExamGrade>(); } if (includeHomeworkAndHolidays) { _holidays = HolidaysOnDay.Create(semesterItems.Items, date); _holidays.CollectionChanged += new WeakEventHandler <NotifyCollectionChangedEventArgs>(_holidays_CollectionChanged).Handler; } else { _holidays = new MyObservableList <ViewItemHoliday>(); } Initialize(schedules, _events, _holidays); }
/// <summary> /// Reset the class reminders. scheduleViewItemsGroup may be null (indicating no semester or reminders disabled). /// </summary> /// <param name="account"></param> /// <param name="scheduleViewItemsGroup"></param> protected abstract void ResetAllReminders(AccountDataItem account, ScheduleViewItemsGroup scheduleViewItemsGroup);
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); } }
private DayScheduleItemsArranger(AccountDataItem account, SemesterItemsViewGroup semesterItems, ScheduleViewItemsGroup scheduleGroup, DateTime date, double heightOfHour, double spacingWhenNoAdditionalItems, double spacingWithAdditionalItems, double widthOfCollapsed, bool includeTasksAndEventsAndHolidays) { if (semesterItems.Semester == null) { throw new NullReferenceException("Semester was null"); } _semesterItems = semesterItems; semesterItems.OnItemsChanged += new WeakEventHandler <EventArgs>(SemesterGroup_OnItemsChanged).Handler; scheduleGroup.OnChangesOccurred += new WeakEventHandler <DataChangedEvent>(ScheduleViewItemsGroup_OnChangesOccurred).Handler; Date = date; _spacingWhenNoAdditionalItems = spacingWhenNoAdditionalItems; _spacingWithAdditionalItems = spacingWithAdditionalItems; _widthOfCollapsed = widthOfCollapsed; Account = account; _schoolTimeZone = account.SchoolTimeZone; HeightOfHour = heightOfHour; MinDuration = TimeSpan.FromHours(widthOfCollapsed / HeightOfHour); IsDifferentSemester = !semesterItems.Semester.IsDateDuringThisSemester(date); SchedulesOnDay schedules = null; if (!IsDifferentSemester) { schedules = SchedulesOnDay.Get(account, semesterItems.Classes, date, account.GetWeekOnDifferentDate(date), trackChanges: true); schedules.CollectionChanged += new WeakEventHandler <NotifyCollectionChangedEventArgs>(Schedules_CollectionChanged).Handler; } _schedules = schedules; if (includeTasksAndEventsAndHolidays) { // For schedules, if tasks have a specific due time, we don't adjust the dates regardless of time zones causing them to switch to a different day, since they're displayed on the visual schedule. Therefore we set useEffectiveDatesEvenWhenItemsHaveTimes to false. _events = TasksOrEventsOnDay.Get(account, semesterItems.Items, date, today: null, activeOnly: false, useEffectiveDateEvenWhenItemsHaveTimes: false); _events.CollectionChanged += new WeakEventHandler <NotifyCollectionChangedEventArgs>(Events_CollectionChanged).Handler; } else { _events = new MyObservableList <BaseViewItemMegaItem>(); } if (includeTasksAndEventsAndHolidays) { _holidays = HolidaysOnDay.Create(semesterItems.Items, date); _holidays.CollectionChanged += new WeakEventHandler <NotifyCollectionChangedEventArgs>(_holidays_CollectionChanged).Handler; } else { _holidays = new MyObservableList <ViewItemHoliday>(); } Initialize(schedules, _events, _holidays); }
protected override void ResetAllReminders(AccountDataItem account, ScheduleViewItemsGroup scheduleViewItemsGroup) { var notifier = ToastNotificationManager.CreateToastNotifier(); var group = ClassRemindersGroupPrefix + "." + UWPRemindersExtension.GetId(account); // Clear current scheduled notifications try { var scheduled = notifier.GetScheduledToastNotifications(); foreach (var s in scheduled) { try { if (s.Group == group) { notifier.RemoveFromSchedule(s); } } catch { } } } catch { } if (scheduleViewItemsGroup == null) { return; } // This will be initialized var beforeTime = account.ClassRemindersTimeSpan.GetValueOrDefault(); // Added in 17134 bool isExpirationTimeSupported = ApiInformation.IsPropertyPresent(typeof(ScheduledToastNotification).FullName, "ExpirationTime"); var today = DateTime.Today; var end = today.AddDays(8); // Schedule out for 8 days Dictionary <ViewItemSchedule, XmlDocument> generatedPayloads = new Dictionary <ViewItemSchedule, XmlDocument>(); for (; today.Date < end.Date; today = today.AddDays(1).Date) { // No need to lock changes, if changes occur an exception might occur, but that's fine, reminders would be reset once again anyways var schedulesOnDay = SchedulesOnDay.Get(account, scheduleViewItemsGroup.Classes, today, account.GetWeekOnDifferentDate(today), trackChanges: false); foreach (var s in schedulesOnDay) { var reminderTime = today.Add(s.StartTime.TimeOfDay).Subtract(beforeTime); if (reminderTime >= DateTime.Now.AddSeconds(5)) { XmlDocument payload; if (!generatedPayloads.TryGetValue(s, out payload)) { payload = GeneratePayload(account, s); generatedPayloads[s] = payload; } var notif = new ScheduledToastNotification(payload, reminderTime) { Group = group, Tag = s.Identifier.ToString() + "." + today.ToString("yy-dd-MM") }; if (isExpirationTimeSupported) { notif.ExpirationTime = today.Add(s.EndTime.TimeOfDay); } try { notifier.AddToSchedule(notif); } catch (Exception ex) { // If OS is in a bad state, we'll just stop TelemetryExtension.Current?.TrackException(new Exception("Adding toast to schedule failed: " + ex.Message, ex)); return; } } } } }