/// <summary> /// Finds the next date that the class occurs on. If the class already started today, returns the /// NEXT instance of that class. /// </summary> /// <param name="account"></param> /// <param name="c"></param> /// <returns></returns> public static DateTime?GetNextClassDate(AccountDataItem account, ViewItemClass c) { if (c.Schedules == null || c.Schedules.Count == 0) { return(null); } var now = DateTime.Now; DateTime date = now.Date; // Look up to 2 weeks (and one day) in advance // We include the extra one day since if the class is currently going on, we want the NEXT instance of that class, // which could possibly be 2 weeks out for (int i = 0; i < 15; i++, date = date.AddDays(1)) { var currWeek = account.GetWeekOnDifferentDate(date); // If there's a schedule on that day // (If it's not today, then we're good... otherwise if it's today, // make sure that the class hasn't started yet - if it started, we want the NEXT instance of the class) if (c.Schedules.Any(s => s.DayOfWeek == date.DayOfWeek && (s.ScheduleWeek == Schedule.Week.BothWeeks || s.ScheduleWeek == currWeek) && (date.Date != now.Date || s.StartTime.TimeOfDay > now.TimeOfDay))) { return(date); } } return(null); }
private static DateTime GetDayBeforeReminderTime(DateTime date, AccountDataItem account, IEnumerable <ViewItemSchedule> allSchedules) { date = DateTime.SpecifyKind(date.Date, DateTimeKind.Local); //if they're using custom end times if (account.CustomEndTimes.ContainsKey(date.DayOfWeek)) { return(date.Add(account.CustomEndTimes[date.DayOfWeek]).AddMinutes(10)); } PowerPlannerSending.Schedule.Week week = account.GetWeekOnDifferentDate(date); //otherwise get all the schedules IEnumerable <ViewItemSchedule> schedules; schedules = allSchedules.Where(i => i.DayOfWeek == date.DayOfWeek && (i.ScheduleWeek == week || i.ScheduleWeek == PowerPlannerSending.Schedule.Week.BothWeeks)); // If there aren't any schedules on that day if (!schedules.Any()) { return(date.AddHours(15)); // 3:00 PM is default time for day before reminders } return(date.Add(schedules.Max(i => i.EndTime.TimeOfDay)).AddMinutes(10)); //day before reminders show up 10 mins after last class }
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); }
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; _schoolTimeZone = account.SchoolTimeZone; 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); }
public static ViewItemClass GetFirstClassOnDay(DateTime date, AccountDataItem account, IEnumerable <ViewItemClass> classes) { if (classes == null) { return(null); } var currWeek = account.GetWeekOnDifferentDate(date); var schedules = SchedulesOnDay.Get(classes, date, currWeek, trackChanges: false); return(schedules.FirstOrDefault()?.Class); }
/// <summary> /// Returns true if the class takes place on the specified date. /// </summary> /// <param name="date"></param> /// <param name="c"></param> /// <returns></returns> public static bool DoesClassOccurOnDate(AccountDataItem account, DateTime date, ViewItemClass c) { if (c.Schedules == null || c.Schedules.Count == 0 || account == null) { return(false); } var currWeek = account.GetWeekOnDifferentDate(date); return(c.Schedules.Any(s => s.DayOfWeek == date.DayOfWeek && (s.ScheduleWeek == Schedule.Week.BothWeeks || s.ScheduleWeek == currWeek))); }
public DateTime GetLocalStartDateAndTime(AccountDataItem account, DataItemSemester semester, DataItemClass c) { DateTime startDate; if (!DateValues.IsUnassigned(semester.Start)) { startDate = DateHelpers.ToViewItemTime(account, semester.Start); } else { startDate = DateTime.Today.AddYears(-1); } // If the class has a start date, we use that rather than the semester start date if (!DateValues.IsUnassigned(c.StartDate)) { startDate = DateHelpers.ToViewItemTime(account, c.StartDate); } var currentWeek = account.GetWeekOnDifferentDate(startDate); // If the schedule doesn't occur each week if (this.ScheduleWeek != Schedule.Week.BothWeeks) { // If it's on the wrong week, we'll move it forward 7 days if (currentWeek != this.ScheduleWeek) { startDate = startDate.AddDays(7); } } // Get the date the schedule actually starts on startDate = DateTools.Next(this.DayOfWeek, startDate); return(startDate.Add(this.StartTime.TimeOfDay)); }
public static ViewItemClass GetClosestClassBasedOnSchedule(DateTime now, AccountDataItem account, IEnumerable <ViewItemClass> classes) { if (classes == null) { return(null); } var currWeek = account.GetWeekOnDifferentDate(now); var schedules = SchedulesOnDay.Get(classes, now, currWeek, trackChanges: false); ViewItemSchedule closestBefore = null; ViewItemSchedule closestAfter = null; //look through all schedules foreach (var s in schedules) { //if the class is currently going on if (now.TimeOfDay >= s.StartTime.TimeOfDay && now.TimeOfDay <= s.EndTime.TimeOfDay) { return(s.Class); } //else if the class is in the future, we instantly select it for the after class since it's sorted from earliest to latest else if (s.StartTime.TimeOfDay >= now.TimeOfDay) { // Make sure it's only 10 mins after if ((s.StartTime.TimeOfDay - now.TimeOfDay) < TimeSpan.FromMinutes(10)) { closestAfter = s; } // Regardless we break break; } else { // Make sure it's only 10 mins before if ((now.TimeOfDay - s.EndTime.TimeOfDay) < TimeSpan.FromMinutes(10)) { closestBefore = s; } } } if (closestAfter == null && closestBefore == null) { return(null); } else if (closestAfter == null) { return(closestBefore.Class); } else if (closestBefore == null) { return(closestAfter.Class); } else if ((now.TimeOfDay - closestBefore.EndTime.TimeOfDay) < (closestAfter.StartTime.TimeOfDay - now.TimeOfDay)) { return(closestBefore.Class); } else { return(closestAfter.Class); } }
/// <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); }
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; } } } } }