// Build the animation for the overall draggable dismissable content. Widget _buildAnimation(BuildContext context, Widget child) { return(Transform.translate( offset: _moveAnimation.value, child: child )); }
public override Widget build(int i, float animationValue, Widget widget) { Offset s = CustomLayoutUtils._getOffsetValue(values: this.values, animationValue: animationValue, index: i); return(Transform.translate( offset: s, child: widget )); }
public override Widget build(BuildContext context) { var screenWidth = MediaQuery.of(context).size.width; var windowChildren = new List <Widget> { new Scroller( child: ListView.builder( controller: m_ScrollController, reverse: true, itemCount: m_HasMoreOld ? widget.messages[widget.channel.id].Count + 1 : widget.messages[widget.channel.id].Count, itemBuilder: (ctx, index) => { if (!m_Initialized) { return(new Container()); } if (index == widget.messages[widget.channel.id].Count) { return(new LoadTrigger( () => { var lastMessageId = widget.messages[widget.channel.id].last().id; Get( $"/api/connectapp/v1/channels/{widget.channel.id}/messages?before={lastMessageId}", (GetMessagesResponse getMessagesResponse) => { if (mounted) { using (WindowProvider.of(context) .getScope()) { setState(() => { widget.messages[widget.channel.id] .AddRange( getMessagesResponse.items .Where( item => item.id != lastMessageId ) ); m_MsgsUnreads = 0; m_HasMoreUnreads = true; if (m_PreviousLastMsgId == null) { m_HasMoreUnreads = false; } else { foreach (var m in widget.messages[widget.channel.id]) { if (string.Compare(m.id, m_PreviousLastMsgId) > 0) { ++m_MsgsUnreads; } else { m_HasMoreUnreads = false; break; } } } m_HasMoreOld = getMessagesResponse.hasMore; }); } } }); } )); } var currentMessage = widget.messages[widget.channel.id][index]; var msgTime = ExtractTimeFromSnowflakeId(currentMessage.id.IsNullOrEmpty() ? currentMessage.nonce : currentMessage.id); bool showTime; var isNew = false; if (index == widget.messages[widget.channel.id].Count - 1) { showTime = true; } else { var nextMessage = widget.messages[widget.channel.id][index + 1]; showTime = msgTime - ExtractTimeFromSnowflakeId( nextMessage.id.IsNullOrEmpty() ? nextMessage.nonce : nextMessage.id) > TimeSpan.FromMinutes(5); if (nextMessage.id != null && nextMessage.id == m_PreviousLastMsgId) { isNew = true; } } Action onBuild = null; if (currentMessage.id == m_PreviousLastMsgId) { onBuild = () => { SchedulerBinding.instance.addPostFrameCallback(value => { setState(() => { m_MsgsUnreads = 0; m_HasMoreUnreads = false; }); }); }; } return(new Message( widget.messages[widget.channel.id][index], widget.users, showTime, m_PreviousLastMsgId != widget.channel.lastMessage.id && isNew, msgTime, onBuild )); } ) ), }; if (Window.reconnecting) { windowChildren.Add( new Positioned( left: 0, top: 0, right: 0, child: new Container( color: new Color(0xfffde1df), height: 48, alignment: Alignment.center, child: new Text( "网络未连接,正在连接中", style: new TextStyle( fontSize: 16, color: new Color(0xfff44336), fontFamily: "PingFang" ) ) ) ) ); } var newMsgsCount = Window.NewMessages.Count(msg => msg.author.id != Window.currentUserId); if (newMsgsCount != 0) { windowChildren.Add( new Positioned( bottom: 24, child: new GestureDetector( onTap: () => { Window.NewMessages.ForEach(msg => { Window.Messages[msg.channelId].Insert(0, msg); }); Window.NewMessages.Clear(); setState(); m_ScrollController.animateTo( 0, new TimeSpan(0, 0, 0, 0, 480), Curves.easeInOut ); }, child: new Container( height: 40, padding: EdgeInsets.symmetric(horizontal: 16), decoration: new BoxDecoration( borderRadius: BorderRadius.all(20), boxShadow: new List <BoxShadow> { new BoxShadow( offset: new Offset(0, 1), blurRadius: 6, color: new Color(0x19000000) ), }, color: new Color(0xffffffff) ), child: new Row( mainAxisAlignment: MainAxisAlignment.center, children: new List <Widget> { new Text( $"{newMsgsCount}条新消息未读", style: new TextStyle( color: new Color(0xff2196f3), fontSize: 14, fontFamily: "PingFang" ) ), } ) ) ) ) ); } if (m_MsgsUnreads > 0) { var text = $"{m_MsgsUnreads}"; if (m_HasMoreUnreads) { text += "+"; } text += "条新消息"; windowChildren.Add( new Positioned( top: 24, child: new GestureDetector( onTap: () => { var totalHeight = 0.0f; for (var index = 0; index < widget.messages[widget.channel.id].Count; ++index) { var message = widget.messages[widget.channel.id][index]; if (string.Compare(message.id, m_PreviousLastMsgId) > 0) { var showTime = true; var msgTime = ExtractTimeFromSnowflakeId(message.id.IsNullOrEmpty() ? message.nonce : message.id); if (index != widget.messages[widget.channel.id].Count - 1) { var nextMessage = widget.messages[widget.channel.id][index + 1]; showTime = msgTime - ExtractTimeFromSnowflakeId( nextMessage.id.IsNullOrEmpty() ? nextMessage.nonce : nextMessage.id) > TimeSpan.FromMinutes(5); } var layoutWidth = screenWidth * 0.7f; if (screenWidth >= 750) { layoutWidth -= 286.5f; } else { layoutWidth -= 24f; } totalHeight += CalculateMessageHeight( message, showTime, layoutWidth ); } else { break; } } if (m_HasMoreUnreads) { totalHeight += 40; } else { totalHeight += 36; } m_ScrollController.animateTo( totalHeight - MediaQuery.of(context).size.height + 184, new TimeSpan(0, 0, 0, 0, 480), Curves.easeInOut ); if (!m_HasMoreUnreads) { setState(() => { m_MsgsUnreads = 0; m_HasMoreUnreads = false; }); } }, child: new Container( height: 40, padding: EdgeInsets.symmetric(horizontal: 16), decoration: new BoxDecoration( borderRadius: BorderRadius.all(20), boxShadow: new List <BoxShadow> { new BoxShadow( offset: new Offset(0, 1), blurRadius: 6, color: new Color(0x19000000) ), }, color: new Color(0xffffffff) ), child: new Row( mainAxisAlignment: MainAxisAlignment.center, children: new List <Widget> { new Text( text, style: new TextStyle( color: new Color(0xff2196f3), fontSize: 14, fontFamily: "PingFang" ) ), new Container( margin: EdgeInsets.only(left: 4), child: Transform.rotate( child: new Icon( IconFont.IconFontArrowUp, size: 24, color: new Color(0xff2196f3) ) ) ) } ) ) ) ) ); } var rootState = HomePage.of(context); var children = new List <Widget> { new Container( color: new Color(0xffffffff), child: new Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: new List <Widget> { new ChattingWindowHeader( widget.channel, () => { if (screenWidth < 750) { m_AnimationController.reverse(); } else { HomePage.of(context).Select(string.Empty); } }), new Expanded( child: new Stack( alignment: Alignment.center, children: windowChildren ) ), new Sender( m_SenderFocusNode, widget.users), } ) ), }; if (!m_Initialized) { children.Add( new Container( alignment: Alignment.center, child: new Loading(size: 56) ) ); } Widget all = new GestureDetector( onTap: () => { FocusScope.of(context).requestFocus(m_EmptyFocusNode); }, child: new Stack( children: children ) ); if (screenWidth < 750) { all = Transform.translate( offset: new Offset((1 - m_AnimationController.value) * screenWidth, 0), child: all ); } return(all); }
public override Widget build(BuildContext context) { var channel = widget.channels[widget.selectedChannelId]; Widget members; var screenSize = MediaQuery.of(context).size; var screenWidth = screenSize.width; var screenHeight = screenSize.height; var containerWidth = screenWidth - 48; if (screenWidth >= 750) { containerWidth -= 375; } var countPerRow = (containerWidth / 240).floor(); var rowCount = ((widget.members.ContainsKey(channel.id) ? widget.members[channel.id].Count : 0) / (float)countPerRow).ceil(); if (!widget.hasMoreMembers.ContainsKey(widget.selectedChannelId)) { widget.hasMoreMembers[widget.selectedChannelId] = true; } if (widget.hasMoreMembers[widget.selectedChannelId]) { rowCount += 1; } members = new SliverList( del: new SliverChildBuilderDelegate( builder: (buildContext, index) => { if (widget.hasMoreMembers[widget.selectedChannelId] && index == rowCount - 1) { return(new Container( height: 78, alignment: Alignment.center, child: new LoadTrigger( onLoad: () => { var offset = widget.members.ContainsKey(channel.id) ? widget.members[channel.id].Count : 0; Utils.Get <GetMembersResponse>( $"/api/connectapp/channels/{channel.id}/members?offset={offset}" ).Then(response => { response.list.ForEach(member => { if (widget.members[channel.id].All(m => m.user.id != member.user.id)) { widget.members[channel.id].Add(member); } widget.users.putIfAbsent(member.user.id, () => member.user); }); m_AmIOwner = widget.members[channel.id].Any(member => member.user.id == Window.currentUserId && member.role == "owner"); widget.hasMoreMembers[widget.selectedChannelId] = response.total > widget.members[channel.id].Count; if (mounted) { using (WindowProvider.of(context).getScope()) { setState(() => { }); } } }); } ) )); } var children = new List <Widget> { }; for (var i = 0; i < countPerRow; ++i) { if (index * countPerRow + i < widget.members[channel.id].Count) { var member = widget.members[channel.id][index * countPerRow + i]; children.Add( new Expanded( child: new Container( height: 78, width: 240, alignment: Alignment.center, child: new Container( height: 50, padding: EdgeInsets.only( top: 6, bottom: 4 ), child: new Row( children: new List <Widget> { new Container( margin: EdgeInsets.only(right: 8), child: new Avatar(member.user) ), new Expanded( child: new Column( crossAxisAlignment: CrossAxisAlignment.start, children: new List <Widget> { new Text( member.user.fullName, style: new TextStyle( fontSize: 14, fontWeight: FontWeight.w500, fontFamily: "PingFang" ), overflow: TextOverflow.ellipsis ), new Text( member.user.title ?? string.Empty, style: new TextStyle( color: new Color(0xff5a5a5b), fontSize: 14, fontFamily: "PingFang" ), overflow: TextOverflow.ellipsis ) } ) ) } ) ) ) ) ); } else { children.Add( new Expanded( child: new Container( height: 78, width: 240 ) ) ); } } return(new Container( margin: EdgeInsets.symmetric(horizontal: 24), decoration: new BoxDecoration( border: new Border( top: new BorderSide( color: new Color(0xfff0f0f0) ) ) ), child: new Row( mainAxisAlignment: MainAxisAlignment.start, children: children ) )); }, childCount: rowCount ) ); var headerChildren = new List <Widget> { new Expanded( child: new Text( $"{channel.name}", style: new TextStyle( fontSize: 16, fontWeight: FontWeight.w500, color: new Color(0xff212121), fontFamily: "PingFang" ) ) ), }; headerChildren.Add( new GestureDetector( onTap: () => { if (screenWidth < 750) { m_AnimationController.reverse(); } else { HomePage.of(this.context).HideChannelInfo(); } }, child: new Icon( IconFont.IconFontClose, color: new Color(0xff979a9e), size: 28 ) ) ); Widget all = new Container( color: new Color(0xffffffff), child: new Scroller( child: new CustomScrollView( slivers: new List <Widget> { new SliverToBoxAdapter( child: new Container( height: 64, decoration: new BoxDecoration( border: new Border( bottom: new BorderSide( color: new Color(0xffd8d8d8) ) ) ), padding: EdgeInsets.symmetric(horizontal: 24), alignment: Alignment.center, child: new Row( crossAxisAlignment: CrossAxisAlignment.center, children: headerChildren ) ) ), MediaQuery.of(context).size.width < 750 ? BuildNarrowInfo() : BuildWideInfo(), new SliverToBoxAdapter( child: new Container( decoration: new BoxDecoration( border: new Border( top: new BorderSide( color: new Color(0xffd8d8d8) ), bottom: new BorderSide( color: new Color(0xffd8d8d8) ) ) ), padding: EdgeInsets.symmetric(vertical: 18), margin: EdgeInsets.symmetric(horizontal: 24), height: 78, child: new Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: new List <Widget> { new Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: new List <Widget> { new Text( "消息免打扰", style: new TextStyle( fontSize: 14, color: new Color(0xff212121), fontFamily: "PingFang" ) ), new Text( "打开后,将不会收到消息提醒", style: new TextStyle( fontSize: 14, color: new Color(0xff797979), fontFamily: "PingFang" ) ), } ), new Switch( m_MuteController ) } ) ) ), new SliverToBoxAdapter( child: new Container( decoration: new BoxDecoration( border: new Border( bottom: new BorderSide( color: new Color(0xffd8d8d8) ) ) ), padding: EdgeInsets.symmetric(vertical: 18), margin: EdgeInsets.symmetric(horizontal: 24), height: 78, child: new Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: new List <Widget> { new Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: new List <Widget> { new Text( "设为置顶", style: new TextStyle( fontSize: 14, color: new Color(0xff212121), fontFamily: "PingFang" ) ), new Text( "打开后,当前群聊将会被置顶在群聊列表", style: new TextStyle( fontSize: 14, color: new Color(0xff797979), fontFamily: "PingFang" ) ) } ), new Switch( m_PinController ) } ) ) ), new SliverToBoxAdapter( child: new Container( margin: EdgeInsets.only(top: 24, left: 24, right: 24), padding: EdgeInsets.only(bottom: 8), child: new Text( $"群聊成员({channel.memberCount})", style: new TextStyle( fontSize: 18, fontWeight: FontWeight.w500, fontFamily: "PingFang" ) ) ) ), members, new SliverToBoxAdapter( child: new Container( height: 56 ) ) } ) ) ); var stacked = new List <Widget> { all }; if (!m_AmIOwner) { var quitButtonChildren = new List <Widget>(); if (m_Quiting) { quitButtonChildren.Add( new Text( "退出群聊", style: new TextStyle( fontSize: 18, color: new Color(0x00000000), fontFamily: "PingFang" ) ) ); quitButtonChildren.Add( new Loading( size: 24 ) ); } else { quitButtonChildren.Add(new Text( "退出群聊", style: new TextStyle( fontSize: 18, color: new Color(0xfff44336), fontFamily: "PingFang" ) ) ); } stacked.Add( new Positioned( bottom: 0, left: 0, right: 0, child: new GestureDetector( onTap: () => { if (m_Quiting) { return; } setState(() => m_Quiting = true); var requestUrl = string.IsNullOrEmpty(channel.groupId) ? $"/api/connectapp/v1/channels/{channel.id}/leave" : $"/api/connectapp/v1/groups/{channel.groupId}/leave"; var state = HomePage.of(context); Utils.Post <Models.Channel>( requestUrl, "{}" ).Then(c => { state.Select(string.Empty); state.RemoveChannel(channel); }); }, child: new Container( height: 56, decoration: new BoxDecoration( color: new Color(0xffffffff), border: new Border( top: new BorderSide( color: new Color(0xffd8d8d8) ) ) ), alignment: Alignment.center, child: new Stack( children: quitButtonChildren ) ) ) ) ); } all = new Stack( children: stacked ); if (screenWidth < 750) { all = Transform.translate( offset: new Offset(0, (1 - m_AnimationController.value) * screenHeight), child: all ); } return(all); }
public override Widget build(BuildContext context) { var screenSize = MediaQuery.of(context).size; var screenWidth = screenSize.width; var screenHeight = screenSize.height; var headerChildren = new List <Widget> { new Expanded( child: new Text( $"{channel?.name ?? string.Empty}", style: new TextStyle( fontSize: 16, fontWeight: FontWeight.w500, color: new Color(0xff212121), fontFamily: "PingFang" ) ) ), }; headerChildren.Add( new GestureDetector( onTap: () => { if (screenWidth < 750) { m_AnimationController.reverse(); } else { HomePage.of(this.context).HideChannelInfo(); } }, child: new Icon( IconFont.IconFontClose, color: new Color(0xff979a9e), size: 28 ) ) ); var children = new List <Widget> { }; if (channel == null) { children.Add( new Loading(size: 56) ); } else { children.Add( CreateLobbyIcon( channel.thumbnail, size: 184, radius: 4 ) ); children.Add( new Container( margin: EdgeInsets.only(top: 32), child: new Text( channel.name, style: new TextStyle( color: new Color(0xff000000), fontSize: 24, fontWeight: FontWeight.bold ) ) ) ); children.Add( new Container( margin: EdgeInsets.only(top: 8), child: new Text( $"{channel.memberCount}成员", style: new TextStyle( color: new Color(0xff797979), fontSize: 14 ) ) ) ); var topic = channel.topic; if (!channel.groupId.IsNullOrEmpty() && group != null) { topic = group.description; } children.Add( new Container( margin: EdgeInsets.only(top: 32), child: new Text( topic, style: new TextStyle( color: new Color(0xff000000), fontSize: 14 ) ) ) ); var buttonChildren = new List <Widget>(); if (m_Joining) { buttonChildren.Add( new Text( "加入群聊", style: new TextStyle( color: new Color(0x00000000), fontSize: 18, fontFamily: "PingFang" ) ) ); buttonChildren.Add( new Loading( size: 24 ) ); } else { buttonChildren.Add( new Text( "加入群聊", style: new TextStyle( fontSize: 18, color: new Color(0xff2196f3), fontFamily: "PingFang" ) ) ); } children.Add( new GestureDetector( onTap: () => { if (m_Joining) { return; } setState(() => m_Joining = true); var requestUrl = string.IsNullOrEmpty(channel.groupId) ? $"/api/connectapp/v1/channels/{channel.id}/join" : $"/api/connectapp/v1/groups/{channel.groupId}/join"; Utils.Post <JoinChannelResponse>( requestUrl, "{}" ).Then(response => { using (WindowProvider.of(context).getScope()) { if (mounted) { var state = HomePage.of(context); var responseChannel = response.channel; state.AddChannel(responseChannel); state.Select(responseChannel.id); state.Ack(responseChannel.id); setState(() => m_Joining = false); } } }); }, child: new Container( height: 56, width: 234, margin: EdgeInsets.only(top: 48), decoration: new BoxDecoration( color: new Color(0xffffffff), borderRadius: BorderRadius.circular(6), border: Border.all( color: new Color(0xff2196f3) ) ), alignment: Alignment.center, child: new Stack( alignment: Alignment.center, children: buttonChildren ) ) ) ); } Widget all = new Container( color: new Color(0xffffffff), child: new Scroller( child: new SingleChildScrollView( child: new Column( children: new List <Widget> { new Container( height: 64, decoration: new BoxDecoration( border: new Border( bottom: new BorderSide( color: new Color(0xffd8d8d8) ) ) ), padding: EdgeInsets.symmetric(horizontal: 24), alignment: Alignment.center, child: new Row( crossAxisAlignment: CrossAxisAlignment.center, children: headerChildren ) ), new Container( constraints: new BoxConstraints( minHeight: screenHeight - 64 ), width: screenWidth < 750 ? (float?)null : 450, margin: EdgeInsets.symmetric(horizontal: 24), alignment: Alignment.center, child: new Column( children: children ) ), } ) ) ) ); var stacked = new List <Widget> { all }; all = new Stack( children: stacked ); if (screenWidth < 750) { all = Transform.translate( offset: new Offset(0, (1 - m_AnimationController.value) * screenHeight), child: all ); } return(all); }
public override Widget build(BuildContext context) { var screenWidth = MediaQuery.of(context).size.width; var headerChildren = new List <Widget> { new Text( "发现群聊", style: HeaderTextStyle ) }; if (screenWidth < 750) { headerChildren.Insert( 0, new GestureDetector( onTap: () => m_AnimationController.reverse(), child: new Container( width: 28, height: 28, margin: EdgeInsets.only(right: 12), child: new Icon( IconFont.IconFontArrowBack, size: 28, color: new Color(0xff979a9e) ) ) ) ); } var children = new List <Widget> { new Container( height: 64, padding: HeaderTextPadding, alignment: Alignment.centerLeft, decoration: new BoxDecoration( border: new Border( bottom: new BorderSide( color: new Color(0xffd8d8d8), width: 1 ) ) ), child: new Row( children: headerChildren ) ), }; if (widget.channels == null || widget.channels.Count == 0) { children.Add( new Expanded( child: new Container( alignment: Alignment.center, child: new Loading( size: 56 ) ) ) ); } else { var canvasWidth = screenWidth - 64; if (screenWidth >= 750) { canvasWidth -= 375; } var countPerRow = (canvasWidth / 316).floor(); var itemWidth = canvasWidth / (float)countPerRow - 16; var rowCount = (widget.channels.Count / (float)countPerRow).ceil(); var rows = new List <Widget> { }; for (var i = 0; i < rowCount; ++i) { var items = new List <Widget> { }; for (var j = 0; j < countPerRow && i * countPerRow + j < widget.channels.Count; ++j) { items.Add( new SquareLobbyCard( widget.channels.Values.ToArray()[i * countPerRow + j], widget.channels, widget.groups, itemWidth ) ); } rows.Add( new Row( mainAxisAlignment: MainAxisAlignment.start, children: items ) ); } children.Add( new Expanded( child: new Scroller( child: new SingleChildScrollView( child: new Container( padding: EdgeInsets.all(32), child: new Column( children: rows ) ) ) ) ) ); } Widget all = new Container( color: HeaderBackgroundColor, child: new Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: children ) ); if (screenWidth < 750) { all = Transform.translate( offset: new Offset((1 - m_AnimationController.value) * screenWidth, 0), child: all ); } return(all); }