private static async Task <NotificationModel> ProcessNotification(this Octokit.Notification notification)
        {
            NotificationModel result = null;
            var isIssue = notification.Subject.Type.ToLower() == "issue";
            var isPR    = notification.Subject.Type.ToLower() == "pullrequest";

            if (int.TryParse(notification.Subject.Url.Split('/').Last().Split('#').First(), out int number))
            {
                var subtitle = "";
                var repo     = notification.Repository;
                var repoName = repo.FullName ?? repo.Name;
                if (isIssue)
                {
                    var issue = await IssueUtility.GetIssue(repo.Id, number);

                    subtitle = $"Issue {number}";
                    result   = new NotificationModel(repo.Id, issue, subtitle);
                }
                else if (isPR)
                {
                    var pr = await PullRequestUtility.GetPullRequest(repo.Id, number);

                    subtitle = $"PR {number}";
                    result   = new NotificationModel(repo.Id, pr, subtitle);
                }
                subtitle = !StringHelper.IsNullOrEmptyOrWhiteSpace(subtitle)
                          ? $"{subtitle} in {repoName}"
                          : repoName;
                result.SetSubtitle(subtitle);
            }

            return(result ?? throw new NullReferenceException(nameof(result)));
        }
        internal NotificationItemViewModel(Notification notification, Action<NotificationItemViewModel> gotoAction, Action<NotificationItemViewModel> deleteAction)
        {
            Notification = notification;
            Title = notification.Subject.Title;
            Id = notification.Id;

            GoToCommand = ReactiveCommand.Create().WithSubscription(_ => gotoAction(this));
            RemoveCommand = ReactiveCommand.Create().WithSubscription(_ => deleteAction(this));

            var subject = notification.Subject.Type.ToLower();
            if (subject.Equals("issue"))
                Type = NotificationType.Issue;
            else if (subject.Equals("pullrequest"))
                Type = NotificationType.PullRequest;
            else if (subject.Equals("commit"))
                Type = NotificationType.Commit;
            else if (subject.Equals("release"))
                Type = NotificationType.Release;
            else
                Type = NotificationType.Unknown;

            try
            {
                UpdatedAt = DateTimeOffset.Parse(notification.UpdatedAt).LocalDateTime.Humanize();
            }
            catch
            {
                // Back up plan?
                UpdatedAt = DateTimeOffset.Now.LocalDateTime.Humanize();
            }
        }
        public static async Task ShowToasts(this ICollection <Octokit.Notification> collection, BackgroundTaskDeferral deferral = null)
        {
            if (collection == null)
            {
                throw new NullReferenceException($"${nameof(collection)} cannot be null");
            }

            collection = new ObservableCollection <Octokit.Notification>(collection.OrderBy(n => n.UpdatedAt));
            var toastNotifications = ToastNotificationManager.History.GetHistory();

            if (toastNotifications != null && toastNotifications.Count > 0)
            {
                foreach (var toast in toastNotifications)
                {
                    Octokit.Notification notification = null;
                    try
                    {
                        notification = await toast.GetNotification();
                    }
                    finally
                    {
                        if (notification != null && collection != null && !collection.Any(n => n.Id == notification.Id))
                        {
                            ToastNotificationManager.History.Remove(toast.Tag, toast.Group);
                        }
                    }
                }
                toastNotifications = ToastNotificationManager.History.GetHistory();
            }
            if (collection != null && collection.Count() > 0)
            {
                foreach (var notification in collection)
                {
                    ToastNotification toast = null;
                    try
                    {
                        toast = await notification.BuildToast(ToastNotificationScenario.Reminder);
                    }
                    finally
                    {
                        if (toast != null && toastNotifications != null && !toastNotifications.Any(t => t.Tag == toast.Tag && t.Group == toast.Group))
                        {
                            ToastHelper.PopCustomToast(toast, toast.Tag, toast.Group);
                        }
                    }
                }
            }

            if (deferral != null)
            {
                deferral?.Complete();
            }
        }
        public static async Task <ToastNotification> BuildToast(this Octokit.Notification notification, string scenario = "default")
        {
            NotificationModel processedNotification = null;
            Issue             issue = null;
            PullRequest       pr    = null;
            User user     = null,
                 closedBy = null;
            DateTimeOffset stateTime;
            var            repoId         = notification.Repository.Id;
            var            notificationId = notification.Id;
            var            itemNumber     = int.Parse(notification.Subject.Url.Split('/').Last().Split('#').First());
            string         title          = null,
                           subtitle         = null,
                           body             = null,
                           status           = null,
                           icon             = null,
                           launchArgs       = $"notificationId={notificationId}&repoId={repoId}",
                           readArgs         = $"notificationId={notificationId}&repoId={repoId}",
                           tag              = $"N{notificationId}+R{repoId}",
                           group            = null,
                           stateTimeString  = null,
                           dateformatString = "dd'/'MM'/'yy H:mm:ss zzz";

            var isIssue = notification.Subject.Type.ToLower().Equals("issue");
            var isPR    = notification.Subject.Type.ToLower().Equals("pullrequest");

            processedNotification = await notification.ProcessNotification();

            if (isIssue)
            {
                issue    = processedNotification.Issue;
                title    = SecurityElement.Escape(issue.Title);
                subtitle = SecurityElement.Escape(processedNotification.Subtitle);
                body     = issue.Body;
                user     = await UserService.GetUserInfo(issue.User.Login);

                launchArgs     += $"&action=showIssue&issueNumber={issue.Number}";
                readArgs       += $"&action=markIssueAsRead&issueNumber={issue.Number}";
                tag            += $"+I{issue.Number}";
                group           = "Issues";
                stateTime       = (issue.ClosedAt ?? issue.UpdatedAt) ?? issue.CreatedAt;
                stateTime       = stateTime.ToLocalTime();
                stateTimeString = stateTime.ToString(dateformatString);
                if (issue.State.StringValue.ToLower() == "open")
                {
                    icon   = "git-issue-opened.png";
                    status = $"opened by {user.Name ?? user.Login} at {stateTimeString}";
                }
                else if (issue.State.StringValue.ToLower() == "reopened")
                {
                    icon   = "git-issue-reopened.png";
                    status = $"re-opened by {user.Name ?? user.Login} at {stateTimeString}";
                }
                else if (issue.State.StringValue.ToLower() == "closed")
                {
                    icon     = "git-issue-closed.png";
                    closedBy = issue.ClosedBy;
                    status   = $"closed by {closedBy.Name ?? closedBy.Login} at {stateTimeString}";
                }
            }
            else if (isPR)
            {
                pr       = processedNotification.PullRequest;
                title    = SecurityElement.Escape(pr.Title);
                subtitle = SecurityElement.Escape(processedNotification.Subtitle);
                body     = pr.Body;
                user     = await UserService.GetUserInfo(pr.User.Login);

                launchArgs     += $"&action=showPr&prNumber={pr.Number}";
                readArgs       += $"&action=markPrAsRead&prNumber={pr.Number}";
                tag            += $"+P{pr.Number}";
                group           = "PullRequests";
                stateTime       = (pr.ClosedAt ?? pr.MergedAt) ?? pr.CreatedAt;
                stateTime       = stateTime.ToLocalTime();
                stateTimeString = stateTime.ToString(dateformatString);
                if (pr.State.StringValue.ToLower() == "open")
                {
                    icon   = "git-pull-request.png";
                    status = $"opened by {user.Name ?? user.Login} at {  stateTime.ToLocalTime().ToString() }";
                }
                else if (pr.State.StringValue.ToLower() == "reopened")
                {
                    icon   = "git-pull-request.png";
                    status = $"re-opened by {user.Name ?? user.Login} at {stateTimeString}";
                }
                else if (pr.State.StringValue.ToLower() == "closed")
                {
                    if (pr.Merged)
                    {
                        icon     = "git-merge.png";
                        closedBy = pr.MergedBy;
                        status   = $"merged by {closedBy.Name ?? closedBy.Login} at {stateTimeString}";
                    }
                    else
                    {
                        icon   = "";
                        status = $"closed at {stateTimeString}";
                    }
                }
            }

            body = body
                   .Substring(0, body.Length >= 50 ? 49 : (body.Length == 0 ? 0 : body.Length - 1));

            body       = SecurityElement.Escape(body ?? "");
            launchArgs = SecurityElement.Escape(launchArgs ?? "");
            readArgs   = SecurityElement.Escape(readArgs ?? "");

            var xml = new XmlDocument();

            xml.LoadXml($@"<toast activationType='foreground' launch='{launchArgs}' scenario='{scenario}'>
							<visual baseUri='Assets/Images/git/'>
								<binding template='ToastGeneric'>
									<text>{title ?? ""}</text>
                                    <text placement='attribution'>{subtitle ?? ""}</text>
									<image placement='appLogoOverride' hint-crop='circle' src='{icon}' />						
									<group>						
										<subgroup hint-weight='33'>
											<image hint-crop='circle' src='{user.AvatarUrl ?? ""}' />
									        <text hint-style='headingSubtle' hint-align='center'>{user.Name ?? user.Login}</text>
										</subgroup>
										<subgroup>	
                                            <text hint-style='bodySubtle' hint-align='center' hint-wrap='true'>{status ?? ""}</text>  
									        <text hint-style='body' hint-align='center' hint-wrap='true'>{body ?? ""}</text>
                                        </subgroup>		
									</group>
								</binding>
							</visual>
							<actions>
								<action
									activationType='background'
									arguments='{readArgs ?? ""}'
									content='Mark As Read' />
								<action
									activationType='system'
									arguments='dismiss'
									content='Dismiss' />
							</actions>

					</toast>"                    );
            var toast = new ToastNotification(xml)
            {
                Tag   = tag,
                Group = group
            };

            return(processedNotification != null
                 ? toast
                 : throw new NullReferenceException());
        }
 public static async Task <ToastNotification> BuildToast(this Octokit.Notification notification, ToastNotificationScenario scenario = ToastNotificationScenario.Default)
 {
     return(await BuildToast(notification, scenario.ToString().ToLower()));
 }
        public static async Task <TileNotification> BuildTiles(
            this Octokit.Notification notification,
            TilesTextStyles titleStyle                    = TilesTextStyles.Title,
            TilesTextStyles subTitleStyle                 = TilesTextStyles.BodySubtle,
            TilesTextStyles bodyStyle                     = TilesTextStyles.Body,
            TilesVisualBrandings visualBindings           = TilesVisualBrandings.NameAndLogo,
            TilesBindingHintPresentation?hintPresentation = null)
        {
            int newIssuesCount    = 0,
                newPrCount        = 0;
            var    isIssue        = notification.Subject.Type.ToLower().Equals("issue");
            var    repoId         = notification.Repository.Id;
            var    itemNumber     = 0;
            User   user           = null;
            string title          = null,
                   subtitle       = null,
                   body           = null,
                   status         = null,
                   notificationId = notification.Id,
                   icon           = null;

            var tile = new TileNotification(new XmlDocument());

            if (isIssue)
            {
                newIssuesCount++;
                var threadId       = int.Parse(notification.Subject.Url.Split('/').Last().Split('?').First());
                var processedIssue = await notification.ProcessNotification();

                var issue = processedIssue.Issue;
                itemNumber = issue.Number;
                user       = await UserService.GetUserInfo(issue.User.Login);

                title    = SecurityElement.Escape(issue.Title);
                subtitle = SecurityElement.Escape(processedIssue.Subtitle);
                body     = issue.Body;
                status   = issue.State.StringValue;
                tile.Tag = $"I{issue.Id}+R{repoId}";
                icon     = status.ToLower() == "closed"
                     ? "git-issue-closed.png"
                     : (status.ToLower() == "reopened"
                       ? "git-issue-reopened.png"
                       : "git-issue-opened.png");
            }
            else
            {
                newPrCount++;
                var processedPR = await notification.ProcessNotification();

                var pr = processedPR.PullRequest;
                itemNumber = pr.Number;
                user       = await UserService.GetUserInfo(pr.User.Login);

                title    = SecurityElement.Escape(pr.Title);
                subtitle = SecurityElement.Escape(processedPR.Subtitle);
                body     = pr.Body;
                status   = pr.State.StringValue;
                tile.Tag = $"P{pr.Id}+R{repoId}";
                icon     = status.ToLower() == "open"
                      ? "git-pull-request.png"
                      : "git-merge.png";
            }
            body = SecurityElement.Escape(
                body
                .Substring(
                    0,
                    body.Length >= 50
                                         ? 49
                                         : (body.Length == 0
                                           ? 0 :
                                            body.Length - 1)
                    )
                );

            string titleStyleString       = titleStyle.ToString().ToLower(),
                   subTitleStyleString    = subTitleStyle.ToString().ToLower(),
                   bodyStyleString        = bodyStyle.ToString().ToLower(),
                   brandingsString        = visualBindings.ToString().ToLower(),
                   hintPresentationString = hintPresentation != null?hintPresentation.Value.ToString().ToLower() : null,
                   hintPresentationAttr   = hintPresentation != null ? $"hint-presentation='{hintPresentationString}'" : null;


            var docXml = $@"
                <tile version='3'>
                    <visual branding='{brandingsString}' baseUri='Assets/Images/git/'>

                        <binding template='TileMedium'>
                            <image placement='peek' src='{user.AvatarUrl}' />
                            <group>
                                <subgroup hint-weight='33'>
                                    <image src='{icon}' />
                                </subgroup>
                                <subgroup>
                                    <text hint-style='{titleStyleString}'>
                                        {title}
                                    </text>
                                    <text hint-style='{subTitleStyleString}'>
                                        {subtitle}
                                    </text>
                                    <text hint-style='{subTitleStyleString}'>
                                        {notification.Repository.FullName}
                                    </text>
                                </subgroup>
                            </group>
                        </binding>

                        <binding template='TileLarge'>
                            <image placement='background' src='{user.AvatarUrl}' />
                            <group>
                                <subgroup hint-weight='33'>
                                    <image src='{icon}' />
                                </subgroup>
                                <subgroup>
                                    <text hint-style='{titleStyleString}'>
                                        {title}
                                    </text>
                                    <text hint-style='{subTitleStyleString}'>
                                        {subtitle}
                                    </text>
                                    <text hint-style='{subTitleStyleString}'>
                                        {notification.Repository.FullName}
                                    </text>
                                    <text hint-style='{subTitleStyleString}' hint-wrap='true' hint-maxLines='3'>
                                        {body}
                                    </text>
                                </subgroup>
                            </group>
                        </binding>

                        <binding template='TileWide'>
                            <image placement='background' src='{user.AvatarUrl}' />
                            <group>
                                <subgroup hint-weight='33'>
                                    <image src='{icon}' />
                                </subgroup>
                                <subgroup>
                                    <text hint-style='{titleStyleString}'>
                                        {title}
                                    </text>
                                    <text hint-style='{subTitleStyleString}'>
                                        {subtitle}
                                    </text>
                                    <text hint-style='{subTitleStyleString}'>
                                        {notification.Repository.FullName}
                                    </text>
                                    <text hint-style='{subTitleStyleString}' hint-wrap='true' hint-maxLines='5'>
                                        {body}
                                    </text>
                                </subgroup>
                            </group>
                        </binding>

                    </visual>
                </tile>";

            tile.Content.LoadXml(docXml);
            return(tile);
        }
 public NotificationTileViewModel(Notification model)
 {
     Model = model;
     Title = model.Subject.Title;
 }