示例#1
0
        /// <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 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);
                }
            }