Ejemplo n.º 1
0
        public override void initState()
        {
            base.initState();
            this._refreshController = new RefreshController();
            this._isHaveTitle       = false;
            this._titleHeight       = 0.0f;
            this._controller        = new AnimationController(
                duration: TimeSpan.FromMilliseconds(100),
                vsync: this
                );
            RelativeRectTween rectTween = new RelativeRectTween(
                RelativeRect.fromLTRB(0, navBarHeight, 0, 0),
                RelativeRect.fromLTRB(0, 13, 0, 0)
                );

            this._animation = rectTween.animate(this._controller);
            SchedulerBinding.instance.addPostFrameCallback(_ => {
                this.widget.actionModel.startFetchArticleDetail();
                this.widget.actionModel.fetchArticleDetail(this.widget.viewModel.articleId);
            });
            this._loginSubId = EventBus.subscribe(EventBusConstant.login_success, args => {
                this.widget.actionModel.startFetchArticleDetail();
                this.widget.actionModel.fetchArticleDetail(this.widget.viewModel.articleId);
            });
            this._jumpState             = _ArticleJumpToCommentState.Inactive;
            this._cachedCommentPosition = null;
        }
Ejemplo n.º 2
0
        Widget _buildNavigationBar(bool isShowRightWidget = true)
        {
            Widget titleWidget = new Container();

            if (this._isHaveTitle)
            {
                titleWidget = new Text(
                    this._article.title,
                    style: CTextStyle.PXLargeMedium,
                    maxLines: 1,
                    overflow: TextOverflow.ellipsis,
                    textAlign: TextAlign.center
                    );
            }

            Widget rightWidget = new Container();

            if (isShowRightWidget)
            {
                string rightWidgetTitle = this._article.commentCount > 0
                    ? $"{this._article.commentCount}个评论"
                    : "评论";
                rightWidget = new Container(
                    margin: EdgeInsets.only(8, right: 16),
                    child: new CustomButton(
                        padding: EdgeInsets.zero,
                        onPressed: () => {
                    //do not jump if we are already at the exact comment position
                    if (this._refreshController.scrollController.position.pixels ==
                        this._cachedCommentPosition)
                    {
                        return;
                    }

                    //first frame: create a new scroll view in which the center of the viewport is the comment widget
                    this.setState(
                        () => { this._jumpState = _ArticleJumpToCommentState.active; });

                    SchedulerBinding.instance.addPostFrameCallback((TimeSpan value2) => {
                        //calculate the comment position = curPixel(0) - minScrollExtent
                        var commentPosition = -this._refreshController.scrollController.position
                                              .minScrollExtent;

                        //cache the current comment position
                        this._cachedCommentPosition = commentPosition;

                        //second frame: create a new scroll view which starts from the default first widget
                        //and then jump to the calculated comment position
                        this.setState(() => {
                            this._refreshController.scrollController.jumpTo(commentPosition);

                            //assume that when we jump to the comment, the title should always be shown as the header
                            //this assumption will fail when an article is shorter than 16 pixels in height (as referred to in _onNotification
                            this._controller.forward();
                            this._isHaveTitle = true;
                        });
                    });
                },
                        child: new Container(
                            width: 88,
                            height: 28,
                            alignment: Alignment.center,
                            decoration: new BoxDecoration(
                                border: Border.all(CColors.PrimaryBlue),
                                borderRadius: BorderRadius.all(14)
                                ),
                            child: new Text(
                                data: rightWidgetTitle,
                                style: new TextStyle(
                                    fontSize: 14,
                                    fontFamily: "Roboto-Medium",
                                    color: CColors.PrimaryBlue
                                    )
                                )
                            )
                        )
                    );
            }
            return(new CustomAppBar(
                       () => this.widget.actionModel.mainRouterPop(),
                       new Expanded(
                           child: new Stack(
                               fit: StackFit.expand,
                               children: new List <Widget> {
                new PositionedTransition(
                    rect: this._animation,
                    child: titleWidget
                    )
            }
                               )
                           ),
                       rightWidget: rightWidget,
                       this._isHaveTitle ? CColors.Separator2 : CColors.Transparent
                       ));
        }
Ejemplo n.º 3
0
        public override Widget build(BuildContext context)
        {
            this.widget.viewModel.articleDict.TryGetValue(this.widget.viewModel.articleId, out this._article);
            if (this.widget.viewModel.articleDetailLoading && (this._article == null || !this._article.isNotFirst))
            {
                return(new Container(
                           color: CColors.White,
                           child: new CustomSafeArea(
                               child: new Column(
                                   children: new List <Widget> {
                    this._buildNavigationBar(false),
                    new ArticleDetailLoading()
                }
                                   )
                               )
                           ));
            }

            if (this._article == null || this._article.channelId == null)
            {
                return(new Container());
            }

            if (this._article.ownerType == "user")
            {
                if (this._article.userId != null &&
                    this.widget.viewModel.userDict.TryGetValue(this._article.userId, out this._user))
                {
                    this._user = this.widget.viewModel.userDict[this._article.userId];
                }
            }

            if (this._article.ownerType == "team")
            {
                if (this._article.teamId != null &&
                    this.widget.viewModel.teamDict.TryGetValue(this._article.teamId, out this._team))
                {
                    this._team = this.widget.viewModel.teamDict[this._article.teamId];
                }
            }

            if (this._titleHeight == 0f && this._article.title.isNotEmpty())
            {
                this._titleHeight = CTextUtils.CalculateTextHeight(
                    text: this._article.title,
                    textStyle: CTextStyle.H3,
                    MediaQuery.of(context).size.width - 16 * 2, // 16 is horizontal padding
                    null
                    ) + 16;                                     // 16 is top padding
                this.setState(() => { });
            }

            var commentIndex = 0;
            var originItems  = this._article == null ? new List <Widget>() : this._buildItems(context, out commentIndex);

            commentIndex    = this._jumpState == _ArticleJumpToCommentState.active ? commentIndex : 0;
            this._jumpState = _ArticleJumpToCommentState.Inactive;

            var child = new Container(
                color: CColors.Background,
                child: new Column(
                    children: new List <Widget> {
                this._buildNavigationBar(),
                new Expanded(
                    child: new CustomScrollbar(
                        new CenteredRefresher(
                            controller: this._refreshController,
                            enablePullDown: false,
                            enablePullUp: this._article.hasMore,
                            onRefresh: this._onRefresh,
                            onNotification: this._onNotification,
                            children: originItems,
                            centerIndex: commentIndex
                            )
                        )
                    ),
                new ArticleTabBar(this._article.like,
                                  () => {
                    if (!this.widget.viewModel.isLoggedIn)
                    {
                        this.widget.actionModel.pushToLogin();
                    }
                    else
                    {
                        AnalyticsManager.ClickComment("Article", this._article.channelId,
                                                      this._article.title);
                        ActionSheetUtils.showModalActionSheet(new CustomInput(
                                                                  doneCallBack: text => {
                            ActionSheetUtils.hiddenModalPopup();
                            this.widget.actionModel.sendComment(this._article.channelId,
                                                                text,
                                                                Snowflake.CreateNonce(),
                                                                null
                                                                );
                        })
                                                              );
                    }
                },
                                  () => {
                    if (!this.widget.viewModel.isLoggedIn)
                    {
                        this.widget.actionModel.pushToLogin();
                    }
                    else
                    {
                        AnalyticsManager.ClickComment("Article", this._article.channelId,
                                                      this._article.title);
                        ActionSheetUtils.showModalActionSheet(new CustomInput(
                                                                  doneCallBack: text => {
                            ActionSheetUtils.hiddenModalPopup();
                            this.widget.actionModel.sendComment(this._article.channelId,
                                                                text,
                                                                Snowflake.CreateNonce(),
                                                                null
                                                                );
                        })
                                                              );
                    }
                },
                                  () => {
                    if (!this.widget.viewModel.isLoggedIn)
                    {
                        this.widget.actionModel.pushToLogin();
                    }
                    else
                    {
                        if (!this._article.like)
                        {
                            this.widget.actionModel.likeArticle(this._article.id);
                        }
                    }
                },
                                  shareCallback: this.share
                                  )
            }
                    )
                );

            return(new Container(
                       color: CColors.White,
                       child: new CustomSafeArea(
                           child: child
                           )
                       ));
        }
Ejemplo n.º 4
0
        Widget _buildNavigationBar(bool isShowRightWidget = true)
        {
            Widget titleWidget = new Container();

            if (this._isHaveTitle)
            {
                titleWidget = new Text(
                    this._article.title,
                    style: CTextStyle.PXLargeMedium,
                    maxLines: 1,
                    overflow: TextOverflow.ellipsis,
                    textAlign: TextAlign.center
                    );
            }

            Widget rightWidget = new Container();

            if (isShowRightWidget)
            {
                string rightWidgetTitle = this._article.commentCount > 0
                    ? $"{this._article.commentCount} 评论"
                    : "抢个沙发";
                rightWidget = new Container(
                    margin: EdgeInsets.only(8, right: 16),
                    child: new CustomButton(
                        padding: EdgeInsets.zero,
                        onPressed: () => {
                    //do not jump if we are already at the exact comment position
                    if (this._refreshController.scrollController.position.pixels ==
                        this._cachedCommentPosition)
                    {
                        return;
                    }

                    //first frame: create a new scroll view in which the center of the viewport is the comment widget
                    this.setState(
                        () => { this._jumpState = _ArticleJumpToCommentState.active; });

                    SchedulerBinding.instance.addPostFrameCallback((TimeSpan value2) => {
                        //calculate the comment position = curPixel(0) - minScrollExtent
                        var commentPosition = -this._refreshController.scrollController.position
                                              .minScrollExtent;

                        //cache the current comment position
                        this._cachedCommentPosition = commentPosition;

                        //second frame: rebuild a smartRefresher with the cached _cacheCommmentPosition
                        this.setState(() => { this._needRebuildWithCachedCommentPosition = true; });
                    });
                },
                        child: new Container(
                            height: 28,
                            padding: EdgeInsets.symmetric(horizontal: 16),
                            alignment: Alignment.center,
                            decoration: new BoxDecoration(
                                color: CColors.PrimaryBlue,
                                borderRadius: BorderRadius.all(14)
                                ),
                            child: new Text(
                                data: rightWidgetTitle,
                                style: new TextStyle(
                                    fontSize: 14,
                                    fontFamily: "Roboto-Medium",
                                    color: CColors.White
                                    )
                                )
                            )
                        )
                    );
            }

            return(new CustomAppBar(
                       () => this.widget.actionModel.mainRouterPop(),
                       new Expanded(
                           child: new Stack(
                               fit: StackFit.expand,
                               children: new List <Widget> {
                new PositionedTransition(
                    rect: this._animation,
                    child: titleWidget
                    )
            }
                               )
                           ),
                       rightWidget: rightWidget,
                       this._isHaveTitle ? CColors.Separator2 : CColors.Transparent
                       ));
        }
Ejemplo n.º 5
0
        public override Widget build(BuildContext context)
        {
            this.widget.viewModel.articleDict.TryGetValue(key: this.widget.viewModel.articleId,
                                                          value: out this._article);
            if (this.widget.viewModel.articleDetailLoading && (this._article == null || !this._article.isNotFirst))
            {
                return(new Container(
                           color: CColors.White,
                           child: new CustomSafeArea(
                               child: new Column(
                                   children: new List <Widget> {
                    this._buildNavigationBar(false),
                    new ArticleDetailLoading()
                }
                                   )
                               )
                           ));
            }

            if (this._article == null || this._article.channelId == null)
            {
                return(new Container(
                           color: CColors.White,
                           child: new CustomSafeArea(
                               child: new Column(
                                   children: new List <Widget> {
                    this._buildNavigationBar(false),
                    new Flexible(
                        child: new BlankView("帖子不存在", "image/default-history")
                        )
                }
                                   )
                               )
                           ));;
            }

            if (this._article.ownerType == "user")
            {
                if (this._article.userId != null &&
                    this.widget.viewModel.userDict.TryGetValue(this._article.userId, out this._user))
                {
                    this._user = this.widget.viewModel.userDict[key : this._article.userId];
                }
            }

            if (this._article.ownerType == "team")
            {
                if (this._article.teamId != null &&
                    this.widget.viewModel.teamDict.TryGetValue(this._article.teamId, out this._team))
                {
                    this._team = this.widget.viewModel.teamDict[key : this._article.teamId];
                }
            }

            if (this._titleHeight == 0f && this._article.title.isNotEmpty())
            {
                this._titleHeight = CTextUtils.CalculateTextHeight(
                    text: this._article.title,
                    textStyle: CTextStyle.H3,
                    MediaQuery.of(context).size.width - 16 * 2, // 16 is horizontal padding
                    null
                    ) + 16;                                     // 16 is top padding
                this.setState(() => { });
            }

            var commentIndex = 0;
            var originItems  = this._article == null ? new List <Widget>() : this._buildItems(context, out commentIndex);

            commentIndex    = this._jumpState == _ArticleJumpToCommentState.active ? commentIndex : 0;
            this._jumpState = _ArticleJumpToCommentState.Inactive;

            Widget contentWidget;

            //happens at the next frame after user presses the "Comment" button
            //we rebuild a CenteredRefresher so that we can calculate out the comment section's position
            if (this._needRebuildWithCachedCommentPosition == false && commentIndex != 0)
            {
                contentWidget = new CenteredRefresher(
                    controller: this._refreshController,
                    enablePullDown: false,
                    enablePullUp: this._article.hasMore,
                    onRefresh: this._onRefresh,
                    onNotification: this._onNotification,
                    children: originItems,
                    centerIndex: commentIndex
                    );
            }
            else
            {
                //happens when the page is updated or (when _needRebuildWithCachedCommentPosition is true) at the next frame after
                //a CenteredRefresher is created and the comment section's position is estimated
                //we use 0 or this estimated position to initiate the SmartRefresher's init scroll offset, respectively
                D.assert(!this._needRebuildWithCachedCommentPosition || this._cachedCommentPosition != null);
                contentWidget = new SmartRefresher(
                    initialOffset: this._needRebuildWithCachedCommentPosition ? this._cachedCommentPosition.Value : 0f,
                    controller: this._refreshController,
                    enablePullDown: false,
                    enablePullUp: this._article.hasMore,
                    onRefresh: this._onRefresh,
                    onNotification: this._onNotification,
                    child: ListView.builder(
                        physics: new AlwaysScrollableScrollPhysics(),
                        itemCount: originItems.Count,
                        itemBuilder: (cxt, index) => originItems[index]
                        ));
                if (this._needRebuildWithCachedCommentPosition)
                {
                    this._needRebuildWithCachedCommentPosition = false;
                    //assume that when we jump to the comment, the title should always be shown as the header
                    //this assumption will fail when an article is shorter than 16 pixels in height (as referred to in _onNotification
                    this._controller.forward();
                    this._isHaveTitle = true;
                }
            }

            var child = new Container(
                color: CColors.Background,
                child: new Column(
                    children: new List <Widget> {
                this._buildNavigationBar(),
                new Expanded(
                    child: new CustomScrollbar(
                        child: contentWidget
                        )
                    ),
                this._buildArticleTabBar()
            }
                    )
                );

            return(new Container(
                       color: CColors.White,
                       child: new CustomSafeArea(
                           child: child
                           )
                       ));
        }
Ejemplo n.º 6
0
        public override Widget build(BuildContext context)
        {
            this.widget.viewModel.articleDict.TryGetValue(key: this.widget.viewModel.articleId,
                                                          value: out this._article);
            if (this.widget.viewModel.articleDetailLoading && (this._article == null || !this._article.isNotFirst))
            {
                return(new Container(
                           color: CColors.White,
                           child: new CustomSafeArea(
                               child: new Column(
                                   children: new List <Widget> {
                    this._buildNavigationBar(false),
                    new ArticleDetailLoading()
                }
                                   )
                               )
                           ));
            }

            if (this._article == null || this._article.channelId == null)
            {
                return(new Container());
            }

            if (this._article.ownerType == "user")
            {
                if (this._article.userId != null &&
                    this.widget.viewModel.userDict.TryGetValue(this._article.userId, out this._user))
                {
                    this._user = this.widget.viewModel.userDict[key : this._article.userId];
                }
            }

            if (this._article.ownerType == "team")
            {
                if (this._article.teamId != null &&
                    this.widget.viewModel.teamDict.TryGetValue(this._article.teamId, out this._team))
                {
                    this._team = this.widget.viewModel.teamDict[key : this._article.teamId];
                }
            }

            if (this._titleHeight == 0f && this._article.title.isNotEmpty())
            {
                this._titleHeight = CTextUtils.CalculateTextHeight(
                    text: this._article.title,
                    textStyle: CTextStyle.H3,
                    MediaQuery.of(context).size.width - 16 * 2, // 16 is horizontal padding
                    null
                    ) + 16;                                     // 16 is top padding
                this.setState(() => { });
            }

            var commentIndex = 0;
            var originItems  = this._article == null ? new List <Widget>() : this._buildItems(context, out commentIndex);

            commentIndex    = this._jumpState == _ArticleJumpToCommentState.active ? commentIndex : 0;
            this._jumpState = _ArticleJumpToCommentState.Inactive;

            var child = new Container(
                color: CColors.Background,
                child: new Column(
                    children: new List <Widget> {
                this._buildNavigationBar(),
                new Expanded(
                    child: new CustomScrollbar(
                        new CenteredRefresher(
                            controller: this._refreshController,
                            enablePullDown: false,
                            enablePullUp: this._article.hasMore,
                            onRefresh: this._onRefresh,
                            onNotification: this._onNotification,
                            children: originItems,
                            centerIndex: commentIndex
                            )
                        )
                    ),
                this._buildArticleTabBar()
            }
                    )
                );

            return(new Container(
                       color: CColors.White,
                       child: new CustomSafeArea(
                           child: child
                           )
                       ));
        }