Exemple #1
0
        public PeopleTopicView()
        {
            InitializeComponent();
            var click = Observable
                        .FromEventPattern <ItemClickEventArgs>(PeopleTopicsList, nameof(PeopleTopicsList.ItemClick))
                        .Select(x => x.EventArgs.ClickedItem as TopicModel)
                        .ObserveOnCoreDispatcher()
                        .Subscribe(x => PageStack.Next("Right", "Right", typeof(RepliesAndTopicView), x.Id));

            NotifyData.LoadDataTask = async count =>
            {
                var html = await ApiClient.GetFavoriteTopics(NotifyData.CurrentPage);

                var dom = new HtmlParser().ParseDocument(html);
                return(new PagesBaseModel <TopicModel>
                {
                    Pages = DomParse.ParseMaxPage(dom),
                    Entity = DomParse.ParseTopics(dom) ?? new List <TopicModel>()
                });
            };

            _events = new List <IDisposable> {
                click
            };
        }
        public CollectedTopicsFragment()
        {
            InitializeComponent();
            LabelPanel.ItemsSource = _tabs;
            async Task <IEnumerable <TopicModel> > loadData()
            {
                var model = LabelPanel.SelectedItem as CollectedListModel;
                var html  = await ApiClient.GetTopicsWithTab(model.Name);

                var dom = new HtmlParser().ParseDocument(html);

                return(DomParse.ParseTopics(dom));
            }

            var selectionChanged = Observable
                                   .FromEventPattern <SelectionChangedEventArgs>(LabelPanel, nameof(LabelPanel.SelectionChanged))
                                   .SelectMany(x => loadData())
                                   .Retry(10)
                                   .ObserveOnCoreDispatcher()
                                   .Subscribe(x =>
            {
                News.Clear();
                foreach (var item in x)
                {
                    News.Add(item);
                }
            });
            var click = Observable.FromEventPattern <ItemClickEventArgs>(NewsList, nameof(NewsList.ItemClick))
                        .Select(x => x.EventArgs.ClickedItem as TopicModel)
                        .ObserveOnCoreDispatcher()
                        .Subscribe(x => PageStack.Next("Left", "Right", typeof(RepliesAndTopicView), x.Id));
            var refresh = Observable.FromEventPattern <TappedRoutedEventArgs>(Refresh, nameof(Refresh.Tapped))
                          .SelectMany(x => loadData())
                          .Retry(10)
                          .ObserveOnCoreDispatcher()
                          .Subscribe(x =>
            {
                News.Clear();
                foreach (var item in x)
                {
                    News.Add(item);
                }
            });

            LabelPanel.SelectedIndex = 0;

            this.Unloaded += (s, e) =>
            {
                selectionChanged.Dispose();
                click.Dispose();
                refresh.Dispose();
            };
        }
        public PeopleNotificationView()
        {
            InitializeComponent();
            var click = Observable
                        .FromEventPattern <ItemClickEventArgs>(NotificationList, nameof(NotificationList.ItemClick))
                        .Select(x => x.EventArgs.ClickedItem as NotificationModel)
                        .ObserveOnCoreDispatcher()
                        .Subscribe(x => PageStack.Next("Right", "Right", typeof(RepliesAndTopicView), new Tuple <int, int>(x.Topic.Id, x.ReplyFloor)));

            NotifyData.LoadDataTask = async count =>
            {
                var html = await ApiClient.GetNotifications(NotifyData.CurrentPage);

                var dom           = new HtmlParser().ParseDocument(html);
                var header        = dom.GetElementById("Main").QuerySelector("div.header");
                var messages      = int.Parse(header.QuerySelector("strong.gray")?.TextContent ?? "0");
                var pages         = messages % 10 != 0 ? messages / 10 + 1 : messages / 10;
                var notifications = dom.GetElementById("Main").GetElementsByClassName("cell")
                                    .Where(node => node.Id != null).Select(
                    node =>
                {
                    var hrefs      = node.QuerySelectorAll("a");
                    var linkPieces = hrefs[2].GetAttribute("href").Split('/', '#');
                    return(new NotificationModel
                    {
                        Topic = new TopicModel
                        {
                            Id = int.Parse(linkPieces[2])
                        },
                        Member = new MemberModel
                        {
                            Image = node.QuerySelector("img").GetAttribute("src")
                        },
                        Id = int.Parse(node.Id.Replace("n_", "")),
                        Title = node.QuerySelector("span.fade").TextContent,
                        ReplyDate = node.QuerySelector("span.snow").TextContent,
                        Content = node.QuerySelector("div.payload")?.TextContent,
                        ReplyFloor = int.Parse(linkPieces[3].Replace("reply", ""))
                    });
                });
                return(new PagesBaseModel <NotificationModel>
                {
                    Pages = pages,
                    Entity = notifications
                });
            };

            _events = new List <IDisposable> {
                click
            };
        }
Exemple #4
0
        public NodesFragment()
        {
            InitializeComponent();
            var loaded = Observable.FromEventPattern <RoutedEventArgs>(AllNodesFragment, nameof(AllNodesFragment.Loaded))
                         .SelectMany(x => ApiClient.GetNodes())
                         .Retry(10)
                         .Select(x =>
            {
                return(x.GroupBy(y =>
                {
                    var begin = y.Title.Trim().First();
                    if (begin >= 'A' && begin <= 'Z')
                    {
                        return $"{begin}";
                    }
                    if (begin >= 'a' && begin <= 'z')
                    {
                        return $"{(char)(begin + 'A' - 'a')}";
                    }
                    if (begin >= 0 && begin <= 256)
                    {
                        return "0-9";
                    }
                    var first = PinYin.GetFirstPinyin(begin.ToString());
                    return string.IsNullOrEmpty(first) ? "其他" : first;
                })
                       .Select(y => new NodeInGroup {
                    Key = y.Key, NodeContent = y.ToList()
                })
                       .OrderBy(y => y.Key));
            })
                         .ObserveOnCoreDispatcher()
                         .Subscribe(x =>
            {
                SortNodesCVS.Source = x;
                OutView.ItemsSource = SortNodesCVS.View.CollectionGroups;
                InView.ItemsSource  = SortNodesCVS.View;
            });
            var click = Observable.FromEventPattern <ItemClickEventArgs>(InView, nameof(InView.ItemClick))
                        .Select(x => x.EventArgs.ClickedItem as NodeModel)
                        .ObserveOnCoreDispatcher()
                        .Subscribe(x => PageStack.Next("Left", "Right", typeof(OneNodeTopicsView), x));

            this.Unloaded += (s, e) =>
            {
                loaded.Dispose();
                click.Dispose();
            };
        }
        public PeopleNodeView()
        {
            InitializeComponent();
            async Task <IEnumerable <NodeModel> > loadData()
            {
                var html = await ApiClient.GetFavoriteNodes();

                return(new HtmlParser().ParseDocument(html).GetElementById("my-nodes").GetElementsByClassName("grid_item")
                       .Select(
                           child =>
                {
                    var strs = child.TextContent.Split(' ');
                    return new NodeModel
                    {
                        Id = int.Parse(child.Id.Replace("n_", "")),
                        Name = child.GetAttribute("href").Replace("/go/", ""),
                        Image = child.QuerySelector("img").GetAttribute("src"),
                        Title = string.Join("", strs.Take(strs.Length - 1)),
                        Topics = int.Parse(strs.Last())
                    };
                }));
            }

            var load = Observable.FromEventPattern <RoutedEventArgs>(PeopleNodePage, nameof(PeopleNodePage.Loaded))
                       .SelectMany(x => loadData())
                       .Retry(10)
                       .ObserveOnCoreDispatcher()
                       .Subscribe(x => PeopleNodeList.ItemsSource = x);
            var click = Observable
                        .FromEventPattern <ItemClickEventArgs>(PeopleNodeList, nameof(PeopleNodeList.ItemClick))
                        .Select(x => x.EventArgs.ClickedItem as NodeModel)
                        .ObserveOnCoreDispatcher()
                        .Subscribe(x => PageStack.Next("Right", "Right", typeof(OneNodeTopicsView), x));

            _events = new List <IDisposable> {
                load, click
            };
        }
        public UserInfoFragment()
        {
            InitializeComponent();
            async Task <PersonCenterModel> loadData()
            {
                var html = await ApiClient.GetMainPage();

                var right  = new HtmlParser().ParseDocument(html).GetElementById("Rightbar");
                var tables = right.QuerySelectorAll("table");
                var spans  = tables[1].QuerySelectorAll("span.bigger");

                return(new PersonCenterModel
                {
                    Member = new MemberModel
                    {
                        Image = tables[0].QuerySelector("img").GetAttribute("src"),
                        Username = tables[0].QuerySelector("span.bigger").TextContent
                    },
                    CollectedNodes = spans[0].TextContent,
                    CollectedTopics = spans[1].TextContent,
                    NoticePeople = spans[2].TextContent,
                    Money = right.QuerySelector("div#money").QuerySelector("a").InnerHtml,
                    Notifications = right.QuerySelector("a[href='/notifications']").TextContent.Split(' ')
                                    .FirstOrDefault(),
                    IsNotChecked = right.QuerySelector("a[href='/mission/daily']") != null
                });
            }

            var checkIn = Observable.FromEventPattern <TappedRoutedEventArgs>(CheckInItem, nameof(CheckInItem.Tapped))
                          .Select(async x =>
            {
                var html = await ApiClient.GetCheckInInformation();
                var href = new HtmlParser().ParseDocument(html).GetElementById("Main").QuerySelector("input")
                           .GetAttribute("onclick").Replace("location.href = '", "").Replace("';", "").Trim();
                if (href.Contains("/balance"))
                {
                    return(CheckInStatus.Gone);
                }
                var r = await ApiClient.CheckIn($"https://www.v2ex.com{href}", $"https://www.v2ex.com{href}");
                return(CheckInStatus.Success);
            })
                          .ObserveOnCoreDispatcher()
                          .Subscribe(async x =>
            {
                switch (await x)
                {
                case CheckInStatus.Gone:
                    Toast.ShowTips("已经签到");
                    break;

                case CheckInStatus.Success:
                    Toast.ShowTips("签到成功");
                    Observable.FromAsync(y => loadData())
                    .Retry(10)
                    .ObserveOnCoreDispatcher()
                    .Subscribe(y => People = y);
                    break;

                case CheckInStatus.Failure:
                    Toast.ShowTips("签到失败");
                    break;
                }
            }, ex => Toast.ShowTips("签到失败"));
            var cancel = Observable.FromEventPattern <TappedRoutedEventArgs>(CancelItem, nameof(CancelItem.Tapped))
                         .ObserveOnCoreDispatcher()
                         .Subscribe(x =>
            {
                if (Window.Current.Content is ActivityContainer frame)
                {
                    PageStack.Clear();
                    frame.ClearBackStack();
                    frame.Navigate(typeof(UserLoginView));
                }
            });
            var write = Observable.FromEventPattern <TappedRoutedEventArgs>(WriteItem, nameof(WriteItem.Tapped))
                        .Subscribe(x => PageStack.Next("Left", "Right", typeof(WriteTopicView), null));
            var user = Observable.FromEventPattern <TappedRoutedEventArgs>(UserItem, nameof(UserItem.Tapped))
                       .Subscribe(x => PageStack.Next("Left", "Right", typeof(MemberView), People.Member.Username));
            var money = Observable.FromEventPattern <TappedRoutedEventArgs>(MoneyItem, nameof(MoneyItem.Tapped))
                        .Subscribe(x => PageStack.Next("Left", "Right", typeof(MoneyDetailView), null));
            var collectTopic = Observable
                               .FromEventPattern <TappedRoutedEventArgs>(CollectTopicItem, nameof(CollectTopicItem.Tapped))
                               .Subscribe(x => PageStack.Next("Left", "Right", typeof(PeopleTopicView), Convert.ToInt32(People.CollectedTopics)));
            var collectNode = Observable.FromEventPattern <TappedRoutedEventArgs>(CollectNodeItem, nameof(CollectNodeItem.Tapped))
                              .Subscribe(x => PageStack.Next("Left", "Right", typeof(PeopleNodeView), null));
            var message = Observable.FromEventPattern <TappedRoutedEventArgs>(MessageItem, nameof(MessageItem.Tapped))
                          .Subscribe(x => PageStack.Next("Left", "Right", typeof(PeopleNotificationView), null));
            var follower = Observable.FromEventPattern <TappedRoutedEventArgs>(FollowerItem, nameof(FollowerItem.Tapped))
                           .Subscribe(x => PageStack.Next("Left", "Right", typeof(PeopleFollowerView), null));
            var loadInformation = Observable
                                  .FromEventPattern <RoutedEventArgs>(UserInformationFragment, nameof(UserInformationFragment.Loaded))
                                  .SelectMany(x => loadData())
                                  .Retry(10)
                                  .ObserveOnCoreDispatcher()
                                  .Subscribe(x => People = x);
            var refresh = Observable.FromEventPattern <TappedRoutedEventArgs>(Refresh, nameof(Refresh.Tapped))
                          .SelectMany(x => loadData())
                          .Retry(10)
                          .ObserveOnCoreDispatcher()
                          .Subscribe(x => People = x);

            this.Unloaded += (s, e) =>
            {
                checkIn.Dispose();
                cancel.Dispose();
                write.Dispose();
                user.Dispose();
                money.Dispose();
                collectTopic.Dispose();
                collectNode.Dispose();
                message.Dispose();
                follower.Dispose();
                loadInformation.Dispose();
                refresh.Dispose();
            };
        }
        public async Task <Paragraph> HtmlToXaml(string richText)
        {
            const string baseUrl   = "https://www.v2ex.com";
            const string unsafeUrl = "http://www.v2ex.com";
            var          blocks    = new[] { "</p>", "</h1>", "</h2>", "</h2>", "</h3>", "</h4>", "</h5>", "</h6>", "</li>", "</blockquote>" };

            foreach (var block in blocks)
            {
                richText = richText.Replace(block, $"\\r{block}");
            }
            var dom = await new HtmlParser().ParseDocumentAsync(richText);
            await Task.Run(() => GetElements(dom.Body));

            var paragraph = new Paragraph();

            foreach (var render in _renderList)
            {
                Run    run    = null;
                Inline inline = null;
                var    isCode = false;
                foreach (var element in render)
                {
                    switch (element.NodeName)
                    {
                    case "IMG":
                        var img = element as IHtmlImageElement;
                        //var source = img.Source.StartsWith("about:")
                        //    ? $"http:{img.Source.Replace("about:", "")}"
                        //    : img.Source;
                        var source = img.Source;
                        if (source.StartsWith("about:///"))
                        {
                            source = baseUrl + source.Replace("about://", "");
                        }
                        else if (source.StartsWith("about:"))
                        {
                            source = $"https:{source.Replace("about:", "")}";
                        }
                        if (!Uri.IsWellFormedUriString(source, UriKind.Absolute))
                        {
                            break;
                        }
                        var bitmap = new Image
                        {
                            Source  = new BitmapImage(new Uri(source)),
                            Stretch = Stretch.None
                        };
                        var viewBox = new Viewbox
                        {
                            Child            = bitmap,
                            StretchDirection = StretchDirection.DownOnly
                        };
                        viewBox.Tapped += (v, s) =>
                        {
                            PageStack.Next("Right", "Right", typeof(ImageViewerPage), source);
                        };
                        paragraph.Inlines.Add(new InlineUIContainer {
                            Child = viewBox
                        });
                        goto Out;

                    case "BR":
                        paragraph.Inlines.Add(new LineBreak());
                        goto Out;

                    case "#text":
                        run = new Run {
                            Text = element.TextContent
                        };
                        inline = run;
                        break;

                    case "A":
                        var elementAnchor = element as IHtmlAnchorElement;
                        var href          = elementAnchor.Href.StartsWith("about://")
                                ? $"{baseUrl}{elementAnchor.Href.Replace("about://", "")}"
                                : elementAnchor.Href;
                        try
                        {
                            var hrefUri   = new Uri(href);
                            var baseUri   = new Uri(baseUrl);
                            var unsafeUri = new Uri(unsafeUrl);
                            if (hrefUri.Host == baseUri.Host || hrefUri.Host == unsafeUri.Host)
                            {
                                var segments  = hrefUri.Segments;
                                var hyperlink = new Hyperlink
                                {
                                    UnderlineStyle = UnderlineStyle.None,
                                    Foreground     = new SolidColorBrush(Colors.RoyalBlue)
                                };
                                hyperlink.Click += (sender, e) =>
                                {
                                    if (segments[1] == "member/")
                                    {
                                        PageStack.Next("Right", "Right", typeof(MemberView), segments[2]);
                                    }
                                    else if (segments[1] == "t/")
                                    {
                                        PageStack.Next("Right", "Right", typeof(RepliesAndTopicView),
                                                       Convert.ToInt32(segments[2]));
                                    }
                                };
                                hyperlink.Inlines.Add(inline);
                                inline = hyperlink;
                            }
                            else
                            {
                                var hyperlink = new Hyperlink
                                {
                                    UnderlineStyle = UnderlineStyle.None,
                                    Foreground     = new SolidColorBrush(Colors.RoyalBlue),
                                    NavigateUri    = new Uri(href)
                                };
                                hyperlink.Inlines.Add(inline);
                                inline = hyperlink;
                            }
                        }
                        catch
                        {
                            inline = new Run {
                                Text = href
                            };
                        }

                        break;

                    case "STRONG":
                        var bold = new Bold();
                        bold.Inlines.Add(inline);
                        inline = bold;
                        break;

                    case "H1":
                    case "H2":
                    case "H3":
                    case "H4":
                    case "H5":
                    case "H6":
                        var h = new Bold {
                            FontSize = Convert.ToInt32(element.NodeName.Substring(1)) + 15
                        };
                        h.Inlines.Add(inline);
                        inline = h;
                        break;

                    case "CODE":
                        break;

                    case "PRE":
                        var code = new Italic();
                        code.Inlines.Add(inline);
                        inline = code;
                        isCode = true;
                        break;

                    case "LI":
                        var span = new Span();
                        span.Inlines.Add(inline);
                        inline = span;
                        break;
                    }
                }
                if (!isCode)
                {
                    run.Text = run.Text.Replace("\n", "").Replace("\\r", "\n");
                }
                paragraph.Inlines.Add(inline);
                Out :;
            }

            return(paragraph);
        }
Exemple #8
0
        public MainPage()
        {
            InitializeComponent();
            RightPart = RightFrame;
            LeftPart  = LeftPivot;
            PageStack.Next("Right", "Right", typeof(BlankPage), null);
            SystemNavigationManager.GetForCurrentView().BackRequested += (sender, el) =>
            {
                el.Handled = true;
                if (PageStack.CanGoBack)
                {
                    PageStack.Back();
                }
            };
            var leftChanged = Observable
                              .FromEventPattern <SizeChangedEventArgs>(LeftPivot, nameof(LeftPivot.SizeChanged))
                              .ObserveOnCoreDispatcher()
                              .Subscribe(x =>
            {
                var headerpanel      = FindVisualChildren <PivotHeaderPanel>(LeftPivot).ToList();
                var totalwidth       = LeftPivot.ActualWidth;
                headerpanel[0].Width = totalwidth;
                var items            = FindVisualChildren <PivotHeaderItem>(headerpanel[0]).ToList();
                for (var i = 0; i < items.Count; i++)
                {
                    items[i].Width = totalwidth / items.Count - 1;
                }
            });
            var rightChanged = Observable
                               .FromEventPattern <SizeChangedEventArgs>(RightFrame, nameof(RightFrame.SizeChanged))
                               .ObserveOnCoreDispatcher()
                               .Subscribe(x =>
            {
                if (RootGrid.ActualWidth > 600)
                {
                    LeftPivot.Width       = 500;
                    LeftPivot.Visibility  = Visibility.Visible;
                    RightFrame.Visibility = Visibility.Visible;
                    RightFrame.SetValue(RelativePanel.RightOfProperty, LeftPivot);
                    LeftPivot.SetValue(RelativePanel.AlignBottomWithPanelProperty, true);
                    LeftPivot.SetValue(RelativePanel.AlignTopWithPanelProperty, true);
                    LeftPivot.SetValue(RelativePanel.AlignLeftWithPanelProperty, true);
                    LeftPivot.SetValue(RelativePanel.AlignRightWithPanelProperty, false);
                    RightFrame.SetValue(RelativePanel.AlignBottomWithPanelProperty, true);
                    RightFrame.SetValue(RelativePanel.AlignTopWithPanelProperty, true);
                    RightFrame.SetValue(RelativePanel.AlignRightWithPanelProperty, true);
                    RightFrame.SetValue(RelativePanel.AlignLeftWithPanelProperty, false);
                }
                else
                {
                    LeftPivot.Width = double.NaN;
                    if (RightFrame.CanGoBack)
                    {
                        LeftPivot.Visibility  = Visibility.Visible;
                        RightFrame.Visibility = Visibility.Collapsed;
                    }
                    else
                    {
                        LeftPivot.Visibility  = Visibility.Collapsed;
                        RightFrame.Visibility = Visibility.Visible;
                    }

                    LeftPivot.SetValue(RelativePanel.AlignBottomWithPanelProperty, true);
                    LeftPivot.SetValue(RelativePanel.AlignTopWithPanelProperty, true);
                    LeftPivot.SetValue(RelativePanel.AlignLeftWithPanelProperty, true);
                    LeftPivot.SetValue(RelativePanel.AlignRightWithPanelProperty, true);
                    RightFrame.SetValue(RelativePanel.AlignBottomWithPanelProperty, true);
                    RightFrame.SetValue(RelativePanel.AlignTopWithPanelProperty, true);
                    RightFrame.SetValue(RelativePanel.AlignRightWithPanelProperty, true);
                    RightFrame.SetValue(RelativePanel.AlignLeftWithPanelProperty, true);
                }
            });

            _events = new List <IDisposable> {
                leftChanged, rightChanged
            };
        }
Exemple #9
0
        public RepliesAndTopicView()
        {
            InitializeComponent();
            var controls = new List <Control> {
                Send, ReplyText
            };
            var send = Observable.FromEventPattern <RoutedEventArgs>(Send, nameof(Send.Click))
                       .Select(x =>
            {
                controls.ForEach(c => c.IsEnabled = false);
                return(x);
            })
                       .Select(async x =>
            {
                var content = ReplyText.Text;
                if (string.IsNullOrEmpty(content))
                {
                    return(ReplyStatus.TextEmpty);
                }
                var html   = await ApiClient.GetTopicInformation(_id);
                var once   = new HtmlParser().ParseDocument(html).QuerySelector("input[name='once']").GetAttribute("value");
                var pramas = new Dictionary <string, string>
                {
                    { "content", content },
                    { "once", once }
                };
                var text = await ApiClient.ReplyTopic($"https://www.v2ex.com/t{_id}",
                                                      new FormUrlEncodedContent(pramas), _id);
                if (text.Contains("你回复过于频繁了"))
                {
                    return(ReplyStatus.Ban);
                }
                return(ReplyStatus.Success);
            })
                       .ObserveOnCoreDispatcher()
                       .Subscribe(async x =>
            {
                try
                {
                    switch (await x)
                    {
                    case ReplyStatus.Ban:
                        Toast.ShowTips("您被禁言1800秒");
                        break;

                    case ReplyStatus.TextEmpty:
                        Toast.ShowTips("内容不能为空");
                        break;

                    case ReplyStatus.Success:
                        Toast.ShowTips("回复成功");
                        ReplyText.Text = "";
                        break;
                    }
                }
                catch
                {
                    Toast.ShowTips("回复失败");
                }
                finally
                {
                    controls.ForEach(c => c.IsEnabled = true);
                }
            });
            var at = Observable.FromEventPattern <TappedRoutedEventArgs>(UsernamePanel, nameof(UsernamePanel.Tapped))
                     .ObserveOnCoreDispatcher()
                     .Subscribe(x => ReplyText.Text += $"@{(string) (x.Sender as TextBlock).Tag} ");
            var collect = Observable
                          .FromEventPattern <TappedRoutedEventArgs>(CollectedPanel, nameof(CollectedPanel.Tapped))
                          .ObserveOnCoreDispatcher()
                          .Subscribe(async x =>
            {
                try
                {
                    var html       = await ApiClient.GetTopicInformation(_id);
                    var url        = "";
                    var regexFav   = new Regex("<a href=\"(.*)\">加入收藏</a>");
                    var regexUnFav = new Regex("<a href=\"(.*)\">取消收藏</a>");
                    if (regexFav.IsMatch(html))
                    {
                        url = regexFav.Match(html).Groups[1].Value;
                    }
                    if (regexUnFav.IsMatch(html))
                    {
                        url = regexUnFav.Match(html).Groups[1].Value;
                    }
                    await ApiClient.OnlyGet($"https://www.v2ex.com{url}");
                    if (Topic.Collect == "加入\n收藏")
                    {
                        Topic.Collect = "已\n收藏";
                        Toast.ShowTips("收藏成功");
                    }
                    else
                    {
                        Topic.Collect = "加入\n收藏";
                        Toast.ShowTips("取消收藏成功");
                    }
                }
                catch
                {
                    Toast.ShowTips("操作失败");
                }
            });
            var tImageTap = Observable.FromEventPattern <TappedRoutedEventArgs>(TImagePanel, nameof(TImagePanel.Tapped))
                            .ObserveOnCoreDispatcher()
                            .Subscribe(x => PageStack.Next("Right", "Right", typeof(MemberView), TImagePanel.Tag));
            var copyLink = Observable
                           .FromEventPattern <TappedRoutedEventArgs>(CopyLinkPanel, nameof(CopyLinkPanel.Tapped))
                           .ObserveOnCoreDispatcher()
                           .Subscribe(x =>
            {
                var clipBoardText = new DataPackage();
                clipBoardText.SetText(Topic.Url);
                Clipboard.SetContent(clipBoardText);
                Toast.ShowTips("已复制到剪贴板");
            });

            Replies.LoadDataTask = async count =>
            {
                var html = await ApiClient.GetRepliesAndTopicContent(_id, Replies.CurrentPage);

                var main = new HtmlParser().ParseDocument(html).GetElementById("Main");
                if (Replies.MaxPage == 0)
                {
                    try
                    {
                        var match       = Regex.Match(html, "([0-9]{1,}) 条回复");
                        var replyString = match.Success ? match.Groups[1].Value : "0";
                        var maxReply    = int.Parse(replyString);
                        var node        = main.QuerySelector("div.header");
                        var topic       = new TopicModel
                        {
                            Id     = _id,
                            Member = new MemberModel
                            {
                                Image    = node.QuerySelector("img").GetAttribute("src"),
                                Username = node.QuerySelector("a").GetAttribute("href").Split('/')[2]
                            },
                            Title      = node.QuerySelector("h1").TextContent,
                            Url        = $"https://www.v2ex.com/t/{_id}",
                            Postscript = main.QuerySelectorAll("div.subtle").Select(subtle => new TopicModel
                            {
                                Content   = subtle.QuerySelector("div.topic_content").InnerHtml,
                                LastReply = subtle.QuerySelector("span.fade").TextContent
                            }).ToList(),
                            Collect    = main.TextContent.Contains("加入收藏") ? "加入\n收藏" : "已\n收藏",
                            Content    = main.QuerySelector("div.topic_content")?.InnerHtml,
                            Replies    = maxReply,
                            CreateDate = node.QuerySelector("small.gray").TextContent.Split('·')[1]
                        };
                        Topic = topic;
                    }
                    catch
                    {
                        Toast.ShowTips("加载失败,可能无权访问该主题");
                        return(new PagesBaseModel <ReplyModel>
                        {
                            Pages = 0,
                            Entity = new List <ReplyModel>()
                        });
                    }
                }

                var replies = main.QuerySelectorAll("table").Where(table => table.ParentElement.Id != null)
                              .Select(table =>
                {
                    var spans = table.QuerySelectorAll("span");
                    return(new ReplyModel
                    {
                        Id = int.Parse(table.ParentElement.Id.Replace("r_", "")),
                        Avater = table.QuerySelector("img").GetAttribute("src"),
                        Username = table.QuerySelector("strong").TextContent,
                        Content = table.QuerySelector("div.reply_content").InnerHtml.Trim(),
                        Thanks = spans.Length == 3 ? int.Parse(spans[2].TextContent.Replace("♥ ", "")) : 0,
                        Floor = $"#{spans[0].TextContent}",
                        ReplyDate = spans[1].TextContent,
                        IsLz = Topic.Member.Username == table.QuerySelector("strong").TextContent
                    });
                });
                return(new PagesBaseModel <ReplyModel>
                {
                    Pages = Topic.Replies % 100 == 0 ? Topic.Replies / 100 : Topic.Replies / 100 + 1,
                    Entity = replies
                });
            };

            _events = new List <IDisposable> {
                send, at, collect, tImageTap, copyLink
            };
        }
        public MemberView()
        {
            InitializeComponent();
            async Task <MemberModel> loadData()
            {
                var html = await ApiClient.GetMemberInformation(_username);

                var cell   = new HtmlParser().ParseDocument(html).GetElementById("Main").QuerySelector("div.cell");
                var inputs = cell.QuerySelectorAll("input");

                if (!inputs.Any())
                {
                    return new MemberModel
                           {
                               Image    = cell.QuerySelector("img").GetAttribute("src"),
                               Username = cell.QuerySelector("h1").TextContent
                           }
                }
                ;
                return(new MemberModel
                {
                    Image = cell.QuerySelector("img").GetAttribute("src"),
                    Notice = "https://www.v2ex.com" + inputs[0].GetAttribute("onclick").Split('\'')[3],
                    IsNotice = inputs[0].GetAttribute("value"),
                    Block = "https://www.v2ex.com" + inputs[1].GetAttribute("onclick").Split('\'')[3],
                    IsBlock = inputs[1].GetAttribute("value"),
                    Username = cell.QuerySelector("h1").TextContent
                });
            }

            var load = Observable.FromEventPattern <RoutedEventArgs>(MemberPage, nameof(MemberPage.Loaded))
                       .SelectMany(x => loadData())
                       .Retry(10)
                       .ObserveOnCoreDispatcher()
                       .Subscribe(x => Member = x, x => { });
            var notice = Observable.FromEventPattern <RoutedEventArgs>(Notice, nameof(Notice.Tapped))
                         .Select(async x => await ApiClient.OnlyGet(Member.Notice))
                         .ObserveOnCoreDispatcher()
                         .Subscribe(x => Member.IsNotice = "取消特别关注", (Exception ex) => { });
            var block = Observable.FromEventPattern <RoutedEventArgs>(Block, nameof(Block.Tapped))
                        .Select(async x => await ApiClient.OnlyGet(Member.Block))
                        .ObserveOnCoreDispatcher()
                        .Subscribe(x => Member.IsBlock = "取消Block", (Exception ex) => { });
            var info = Observable.FromEventPattern <ItemClickEventArgs>(MemberInfoList, nameof(MemberInfoList.ItemClick))
                       .ObserveOnCoreDispatcher()
                       .Subscribe(x =>
            {
                var item = x.EventArgs.ClickedItem as TopicModel;

                PageStack.Next("Right", "Right", typeof(RepliesAndTopicView), item.Id);
            });

            Topics.LoadDataTask = async count =>
            {
                var html = await ApiClient.GetTopicsByUsername(_username, Topics.CurrentPage);

                if (html.Contains("主题列表被隐藏"))
                {
                    ListHiddenPanel.Visibility = Visibility.Visible;
                    return(new PagesBaseModel <TopicModel>
                    {
                        Pages = 0,
                        Entity = new List <TopicModel>()
                    });
                }

                var dom    = new HtmlParser().ParseDocument(html);
                var pages  = DomParse.ParseMaxPage(dom);
                var topics = dom.GetElementById("Main").GetElementsByClassName("cell item").Select(node =>
                {
                    var hrefs = node.QuerySelectorAll("a");
                    var topic = new TopicModel
                    {
                        Title    = hrefs[0].TextContent,
                        NodeName = hrefs[1].TextContent,
                        Member   = new MemberModel
                        {
                            Username = hrefs[2].TextContent
                        },
                        Id = int.Parse(new Regex("/t/([0-9]*)").Match(hrefs[0].GetAttribute("href")).Groups[1].Value)
                    };
                    if (hrefs.Length == 5)
                    {
                        topic.LastUsername = $"最后回复者 :{hrefs[3].TextContent}";
                        topic.Replies      = int.Parse(hrefs[4].TextContent);
                        var last           = node.QuerySelector("span.topic_info").TextContent.Split('•')[2].Trim();
                        last            = last.Contains("最后回复") ? "" : last;
                        topic.LastReply = $"时间 : {last.Trim()}";
                    }

                    return(topic);
                });
                return(new PagesBaseModel <TopicModel>
                {
                    Pages = pages,
                    Entity = topics
                });
            };
            Notifications.LoadDataTask = async count =>
            {
                var html = await ApiClient.GetRepliesByUsername(_username, Notifications.CurrentPage);

                var dom           = new HtmlParser().ParseDocument(html);
                var main          = dom.GetElementById("Main");
                var nodes         = main.QuerySelectorAll("div.dock_area");
                var replies       = main.QuerySelectorAll("div.reply_content");
                var pages         = DomParse.ParseMaxPage(dom);
                var notifications = nodes.Select(
                    (node, i) =>
                {
                    var href = node.QuerySelector("a");
                    var span = node.QuerySelector("span");
                    return(new NotificationModel
                    {
                        Title = href.TextContent,
                        Content = replies[i].TextContent,
                        ReplyDate = span.TextContent
                    });
                });
                return(new PagesBaseModel <NotificationModel>
                {
                    Pages = pages,
                    Entity = notifications
                });
            };

            _events = new List <IDisposable> {
                load, notice, block, info
            };
        }
        public OneNodeTopicsView()
        {
            InitializeComponent();
            var click = Observable
                        .FromEventPattern <ItemClickEventArgs>(NodeTopcisList, nameof(NodeTopcisList.ItemClick))
                        .Select(x => x.EventArgs.ClickedItem as TopicModel)
                        .ObserveOnCoreDispatcher()
                        .Subscribe(x => PageStack.Next("Right", "Right", typeof(RepliesAndTopicView), x.Id));
            var collect = Observable.FromEventPattern <TappedRoutedEventArgs>(CollectNode, nameof(CollectNode.Tapped))
                          .SelectMany(x => ApiClient.GetNodeInformation(Node.Name))
                          .Select(html =>
            {
                var regexFav   = new Regex("<a href=\"(.*)\">加入收藏</a>");
                var regexUnFav = new Regex("<a href=\"(.*)\">取消收藏</a>");
                var url        = "";
                if (regexFav.IsMatch(html))
                {
                    url = regexFav.Match(html).Groups[1].Value;
                }
                if (regexUnFav.IsMatch(html))
                {
                    url = regexUnFav.Match(html).Groups[1].Value;
                }
                return(url);
            })
                          .SelectMany(url => ApiClient.OnlyGet($"https://www.v2ex.com{url}"))
                          .ObserveOnCoreDispatcher()
                          .Subscribe(x => Node.IsCollect = Node.IsCollect == "加入收藏" ? "取消收藏" : "加入收藏", ex => { });

            NotifyData.LoadDataTask = async count =>
            {
                var html = await ApiClient.GetTopicsWithPageN(Node.Name, NotifyData.CurrentPage);

                var dom = new HtmlParser().ParseDocument(html);
                if (NotifyData.MaxPage == 0)
                {
                    var header = dom.GetElementById("Main").QuerySelector("div.node_header");
                    Node = new NodeModel
                    {
                        Topics    = Convert.ToInt32(header.QuerySelector("strong").TextContent),
                        IsCollect = header.QuerySelector("a").TextContent,
                        Cover     = header.QuerySelector("img") == null
                            ? "ms-appx:///Assets/default.png"
                            : header.QuerySelector("img").GetAttribute("src"),
                        Title = Node.Title,
                        Name  = Node.Name
                    };
                }

                var topics = dom.GetElementById("TopicsNode").Children.Select(node =>
                {
                    var hrefs = node.QuerySelectorAll("a");
                    var imgs  = node.QuerySelector("img.avatar");
                    var topic = new TopicModel
                    {
                        Title  = hrefs[1].TextContent,
                        Member = new MemberModel
                        {
                            Username = hrefs[2].TextContent,
                            Image    = imgs.GetAttribute("src")
                        },
                        Id = int.Parse(node.ClassName.Split('_').Last())
                    };
                    if (hrefs.Length == 5)
                    {
                        topic.LastUsername = $"最后回复者 :{hrefs[3].TextContent}";
                        topic.Replies      = int.Parse(hrefs[4].TextContent);
                        var last           = node.GetElementsByClassName("topic_info").First().TextContent.Split('•')[1].Trim();
                        if (last.Length > 12)
                        {
                            var timeSpan = DateTime.Now - DateTime.Parse(last.Insert(10, " "));
                            last         = $"{(int) timeSpan.TotalDays}天";
                        }

                        topic.LastReply = $"时间 : {last.Trim()}";
                    }

                    return(topic);
                });
                return(new PagesBaseModel <TopicModel>
                {
                    Pages = Node.Topics % 20 == 0 ? Node.Topics / 20 : Node.Topics / 20 + 1,
                    Entity = topics
                });
            };

            _events = new List <IDisposable> {
                collect, click
            };
        }