/// <summary> /// /// </summary> /// <param name="groupedByDay">This list will be modified, removing items that are past the date to start displaying on, which is beneficial to the next time this is called since those removed items would have never been applicable anyways.</param> /// <param name="todayAsUtc"></param> /// <param name="useFriendlyDates"></param> /// <param name="type"></param> /// <param name="tileSettings"></param> /// <returns></returns> internal static XmlDocument GenerateUpcomingTileNotificationContent(List <ItemsOnDay> groupedByDay, DateTime todayAsUtc, bool useFriendlyDates, UpcomingTileType type) { // If there aren't any if (groupedByDay.Count == 0) { return(null); } var mediumAndWideContent = GenerateTileBindingContent( groupedItems: groupedByDay, todayAsUtc: todayAsUtc, useFriendlyDates: useFriendlyDates, useLargerHeader: false, maxLinesOfText: 10); var largeContent = GenerateTileBindingContent( groupedItems: groupedByDay, todayAsUtc: todayAsUtc, useFriendlyDates: useFriendlyDates, useLargerHeader: true, maxLinesOfText: 13); TileContent content = new TileContent() { Visual = new TileVisual() { Branding = type == UpcomingTileType.PrimaryTile ? TileBranding.NameAndLogo : TileBranding.Auto, TileMedium = new TileBinding() { DisplayName = type == UpcomingTileType.PrimaryTile ? "Planner" : null, Content = mediumAndWideContent }, TileWide = new TileBinding() { Content = mediumAndWideContent }, TileLarge = new TileBinding() { Content = largeContent }, LockDetailedStatus1 = GenerateUpcomingDateText(groupedByDay.First().DateInUtc, todayAsUtc, useFriendlyDates) } }; var firstGroup = groupedByDay.First(); if (firstGroup.Items.Count > 1) { content.Visual.LockDetailedStatus1 += " - " + firstGroup.Items.Count + " Items"; } content.Visual.LockDetailedStatus2 = trim(firstGroup.Items[0].Name, 255); if (firstGroup.Items.Count >= 2) { content.Visual.LockDetailedStatus3 = trim(firstGroup.Items[1].Name, 255); } //XmlDocument doc = new XmlDocument(); //string stringContent = content.GetContent(); //doc.LoadXml(stringContent); //return doc; return(content.GetXml()); }
/// <summary> /// /// </summary> /// <param name="updater"></param> /// <param name="allUpcoming">This list will be manipulated. Should already be sorted.</param> /// <param name="todayInLocal"></param> /// <param name="type"></param> internal static void UpdateUpcomingTile(TileUpdater updater, List <BaseViewItemHomeworkExam> allUpcoming, DateTime todayInLocal, UpcomingTileType type, BaseUpcomingTileSettings tileSettings) { try { // Clear all scheduled notifications ClearScheduledNotifications(updater); List <ItemsOnDay> groupedByDay = GroupByDay(allUpcoming); bool veryFirst = true; DateTime today = todayInLocal; const int daysInAdvance = 5; for (int i = 0; i < daysInAdvance; i++, today = today.AddDays(1)) { DateTime todayAsUtc = DateTime.SpecifyKind(today, DateTimeKind.Utc); // Remove any exams that are past "today" for (int x = 0; x < groupedByDay.Count; x++) { groupedByDay[x].Items.RemoveAll(item => item is ViewItemExam && item.Date < today); if (groupedByDay[x].Items.Count == 0) { groupedByDay.RemoveAt(x); x--; } } DateTime dateToStartFrom = tileSettings.GetDateToStartDisplayingOn(todayAsUtc); // Remove any day groups that are older than the user's chosen max date range to display while (groupedByDay.Count > 0 && groupedByDay[0].DateInUtc < dateToStartFrom) { groupedByDay.RemoveAt(0); } // If there's a today group Dictionary <Guid, DateTime> identifiersAndEndTimes = new Dictionary <Guid, DateTime>(); var todayGroup = groupedByDay.FirstOrDefault(g => g.DateInUtc == todayAsUtc); if (todayGroup != null) { // That means we'll need to check if there's exams/events, and if so, we need to update the tile // after the event is over, rather than waiting till the day is over // First we need to create a mapping of the item end times and their indexes, because we need to make sure that we're removing // in order of the earliest end times (right now items are sorted by their start times, so not necessarily correct order based on end times) // We also need to be aware that an event could potentially span multiple days... foreach (var item in todayGroup.Items) { // We ignore "all day" items which end at 11:59:59 DateTime endTime; if (item is ViewItemExam && item.TryGetEndDateWithTime(out endTime) && endTime.TimeOfDay != new TimeSpan(23, 59, 59)) { identifiersAndEndTimes[item.Identifier] = endTime; } } // Remove any events that have already expired (so that the first update doesn't include them) //if (veryFirst) //{ // while (true) // { // if (identifiersAndEndTimes.Count > 0) // { // DateTime minEndTime = identifiersAndEndTimes.Values.Min(); // // If it's already expired, we remove it // if (minEndTime < DateTime.Now) // { // Guid[] identifiersToRemove = identifiersAndEndTimes.Where(p => p.Value == minEndTime).Select(p => p.Key).ToArray(); // foreach (var id in identifiersToRemove) // { // identifiersAndEndTimes.Remove(id); // } // // Remove those events // todayGroup.Items.RemoveAll(x => identifiersToRemove.Contains(x.Identifier)); // // If we've removed all for that day // if (todayGroup.Items.Count == 0) // { // // Remove the group // groupedByDay.Remove(todayGroup); // } // } // } // break; // } //} } DateTime deliveryTime = today; do { if (deliveryTime.Date != today.Date) { // If an event ended up spanning multiple days causing delivery time to be past today, we just won't add it. // In the future when we add support for multiple day events, we'll have to actually handle this... otherwise when the // event expires, the tile won't update correctly on that future day. break; } // On all items but the last, we use the friendly date XmlDocument tile = GenerateUpcomingTileNotificationContent( groupedByDay: groupedByDay, todayAsUtc: todayAsUtc, useFriendlyDates: i != daysInAdvance - 1, type: type); if (tile == null) { if (veryFirst) { updater.Clear(); } return; } DateTime thisDeliveryTime = deliveryTime; DateTime expirationTime = today.AddDays(1); bool hasAdditionalOnThisDay = false; // Pick off earliest ending time if there are any left if (identifiersAndEndTimes.Count > 0) { DateTime minEndTime = identifiersAndEndTimes.Values.Min(); Guid[] identifiersToRemove = identifiersAndEndTimes.Where(p => p.Value == minEndTime).Select(p => p.Key).ToArray(); foreach (var id in identifiersToRemove) { identifiersAndEndTimes.Remove(id); } // Assign the expiration time and the next delivery time to be this end time if (minEndTime > deliveryTime) { expirationTime = minEndTime; deliveryTime = minEndTime; // Setting this for the NEXT notification } // Remove those events todayGroup.Items.RemoveAll(x => identifiersToRemove.Contains(x.Identifier)); // If we've removed all for that day if (todayGroup.Items.Count == 0) { // Remove the group groupedByDay.Remove(todayGroup); } // Otherwise else { // We have more on this day that we'll have to repeat the loop for hasAdditionalOnThisDay = true; } } // If we don't have additional on this day, we can remove today since we're done with it, // which will ensure we correctly set expiration time if there's nothing else left if (!hasAdditionalOnThisDay && todayGroup != null) { groupedByDay.Remove(todayGroup); } if (veryFirst || thisDeliveryTime < DateTime.Now.AddSeconds(5)) { TileNotification currNotif = new TileNotification(tile); // Only assign expiration time if we have no items left if (groupedByDay.Count == 0) { currNotif.ExpirationTime = expirationTime; } updater.Update(currNotif); veryFirst = false; } else { ScheduledTileNotification s = new ScheduledTileNotification(tile, thisDeliveryTime); // Only assign expiration time if we have no items left if (groupedByDay.Count == 0) { s.ExpirationTime = expirationTime; } updater.AddToSchedule(s); } if (!hasAdditionalOnThisDay) { break; } } while (true); } } catch (Exception ex) { if (!UWPExceptionHelper.TrackIfNotificationsIssue(ex, "Tiles")) { throw ex; } } }