예제 #1
0
        public void Calculate(int desiredWidth)
        {
            _posArray.Clear();
            Positions.Clear();
            int count = Messages.Count;

            if (count <= 1)
            {
                return;
            }

            int   totalWidth  = 0;
            float totalHeight = 0.0f;

            _scale        = (float)desiredWidth / _maxSizeWidth;
            _maxSizeWidth = desiredWidth;
            int           firstSpanAdditionalSize = (int)(200 * _scale);
            int           minHeight          = (int)(120 * _scale);
            int           minWidth           = (int)(96 * _scale);
            int           paddingsWidth      = (int)(32 * _scale);
            float         maxSizeHeight      = 814.0f * _scale;
            StringBuilder proportions        = new StringBuilder();
            float         averageAspectRatio = 1.0f;
            bool          isOut     = false;
            int           maxX      = 0;
            bool          forceCalc = false;

            for (int a = 0; a < count; a++)
            {
                int w = 0;
                int h = 0;
                var decryptedMessageObject = Messages[a] as TLDecryptedMessage;
                if (decryptedMessageObject != null)
                {
                    TLVector <TLPhotoSizeBase> photoThumbs = null;
                    var photoMedia    = decryptedMessageObject.Media as TLDecryptedMessageMediaPhoto;
                    var documentMedia = decryptedMessageObject.Media as TLDecryptedMessageMediaDocument;
                    var videoMedia    = decryptedMessageObject.Media as TLDecryptedMessageMediaVideo;
                    if (photoMedia != null)
                    {
                        photoThumbs = new TLVector <TLPhotoSizeBase> {
                            new TLPhotoSize {
                                W = photoMedia.W, H = photoMedia.H
                            }
                        };
                    }
                    else if (documentMedia != null)
                    {
                        photoThumbs = new TLVector <TLPhotoSizeBase> {
                            new TLPhotoSize {
                                W = documentMedia.ThumbW.Value > 0 ? documentMedia.ThumbW : new TLInt(90), H = documentMedia.ThumbH.Value > 0 ? documentMedia.ThumbH : new TLInt(90)
                            }
                        };
                    }
                    else if (videoMedia != null)
                    {
                        photoThumbs = new TLVector <TLPhotoSizeBase> {
                            new TLPhotoSize {
                                W = videoMedia.W.Value > 0 ? videoMedia.W : new TLInt(90), H = videoMedia.H.Value > 0 ? videoMedia.H : new TLInt(90)
                            }
                        };
                    }
                    TLPhotoSizeBase photoSize  = GetClosestPhotoSizeWithSize(photoThumbs, 1280);
                    var             size       = photoSize as TLPhotoSize;
                    var             cachedSize = photoSize as TLPhotoCachedSize;
                    if (size != null)
                    {
                        w = size.W.Value;
                        h = size.H.Value;
                    }
                    else if (cachedSize != null)
                    {
                        w = cachedSize.W.Value;
                        h = cachedSize.H.Value;
                    }
                    GroupedMessagePosition position = new GroupedMessagePosition();
                    position.IsLast      = a == count - 1;
                    position.AspectRatio = w / (float)h;

                    if (position.AspectRatio > 1.2f)
                    {
                        proportions.Append("w");
                    }
                    else if (position.AspectRatio < 0.8f)
                    {
                        proportions.Append("n");
                    }
                    else
                    {
                        proportions.Append("q");
                    }

                    averageAspectRatio += position.AspectRatio;

                    if (position.AspectRatio > 2.0f)
                    {
                        forceCalc = true;
                    }

                    Positions[decryptedMessageObject] = position;
                    _posArray.Add(position);
                }

                var messageObject = Messages[a] as TLMessage;
                if (messageObject != null)
                {
                    TLVector <TLPhotoSizeBase> photoThumbs = null;
                    var photoMedia    = messageObject.Media as TLMessageMediaPhoto;
                    var documentMedia = messageObject.Media as TLMessageMediaDocument;
                    if (photoMedia != null)
                    {
                        var photo = photoMedia.Photo as TLPhoto;
                        if (photo != null)
                        {
                            photoThumbs = photo.Sizes;
                        }
                    }
                    else if (documentMedia != null)
                    {
                        var document = documentMedia.Document as TLDocument;
                        if (document != null)
                        {
                            photoThumbs = new TLVector <TLPhotoSizeBase> {
                                document.Thumb
                            };
                        }
                    }
                    TLPhotoSizeBase photoSize  = GetClosestPhotoSizeWithSize(photoThumbs, 1280);
                    var             size       = photoSize as TLPhotoSize;
                    var             cachedSize = photoSize as TLPhotoCachedSize;
                    if (size != null)
                    {
                        w = size.W.Value;
                        h = size.H.Value;
                    }
                    else if (cachedSize != null)
                    {
                        w = cachedSize.W.Value;
                        h = cachedSize.H.Value;
                    }
                    GroupedMessagePosition position = new GroupedMessagePosition();
                    position.IsLast      = a == count - 1;
                    position.AspectRatio = w / (float)h;

                    if (position.AspectRatio > 1.2f)
                    {
                        proportions.Append("w");
                    }
                    else if (position.AspectRatio < 0.8f)
                    {
                        proportions.Append("n");
                    }
                    else
                    {
                        proportions.Append("q");
                    }

                    averageAspectRatio += position.AspectRatio;

                    if (position.AspectRatio > 2.0f)
                    {
                        forceCalc = true;
                    }

                    Positions[messageObject] = position;
                    _posArray.Add(position);
                }
            }

            //int minHeight = AndroidUtilities.dp(120);
            //int minWidth = (int)(AndroidUtilities.dp(120) / (Math.Min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) / (float)_maxSizeWidth));
            //int paddingsWidth = (int)(AndroidUtilities.dp(40) / (Math.Min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) / (float)_maxSizeWidth));


            float maxAspectRatio = _maxSizeWidth / maxSizeHeight;

            averageAspectRatio = averageAspectRatio / count;

            if (!forceCalc && (count == 2 || count == 3 || count == 4))
            {
                if (count == 2)
                {
                    GroupedMessagePosition position1 = _posArray[0];
                    GroupedMessagePosition position2 = _posArray[1];
                    String pString = proportions.ToString();
                    if (pString.Equals("ww") && averageAspectRatio > 1.4 * maxAspectRatio && position1.AspectRatio - position2.AspectRatio < 0.2)
                    {
                        float height = (float)Math.Round(Math.Min(_maxSizeWidth / position1.AspectRatio, Math.Min(_maxSizeWidth / position2.AspectRatio, maxSizeHeight / 2.0f))) / maxSizeHeight;
                        position1.Set(0, 0, 0, 0, _maxSizeWidth, height, POSITION_FLAG_LEFT | POSITION_FLAG_RIGHT | POSITION_FLAG_TOP);
                        position2.Set(0, 0, 1, 1, _maxSizeWidth, height, POSITION_FLAG_LEFT | POSITION_FLAG_RIGHT | POSITION_FLAG_BOTTOM);

                        totalWidth  = _maxSizeWidth;
                        totalHeight = height * 2;
                    }
                    else if (pString.Equals("ww") || pString.Equals("qq"))
                    {
                        int   width  = _maxSizeWidth / 2;
                        float height = (float)Math.Round(Math.Min(width / position1.AspectRatio, Math.Min(width / position2.AspectRatio, maxSizeHeight))) / maxSizeHeight;
                        position1.Set(0, 0, 0, 0, width, height, POSITION_FLAG_LEFT | POSITION_FLAG_BOTTOM | POSITION_FLAG_TOP);
                        position2.Set(1, 1, 0, 0, width, height, POSITION_FLAG_RIGHT | POSITION_FLAG_BOTTOM | POSITION_FLAG_TOP);
                        maxX = 1;

                        totalWidth  = width + width;
                        totalHeight = height;
                    }
                    else
                    {
                        int secondWidth = (int)Math.Max(0.4f * _maxSizeWidth, Math.Round((_maxSizeWidth / position1.AspectRatio / (1.0f / position1.AspectRatio + 1.0f / position2.AspectRatio))));
                        int firstWidth  = _maxSizeWidth - secondWidth;
                        if (firstWidth < minWidth)
                        {
                            int diff = minWidth - firstWidth;
                            firstWidth   = minWidth;
                            secondWidth -= diff;
                        }

                        float height = (float)Math.Min(maxSizeHeight, Math.Round(Math.Min(firstWidth / position1.AspectRatio, secondWidth / position2.AspectRatio))) / maxSizeHeight;
                        position1.Set(0, 0, 0, 0, firstWidth, height, POSITION_FLAG_LEFT | POSITION_FLAG_BOTTOM | POSITION_FLAG_TOP);
                        position2.Set(1, 1, 0, 0, secondWidth, height, POSITION_FLAG_RIGHT | POSITION_FLAG_BOTTOM | POSITION_FLAG_TOP);
                        maxX = 1;

                        totalWidth  = firstWidth + secondWidth;
                        totalHeight = height;
                    }
                }
                else if (count == 3)
                {
                    GroupedMessagePosition position1 = _posArray[0];
                    GroupedMessagePosition position2 = _posArray[1];
                    GroupedMessagePosition position3 = _posArray[2];
                    if (proportions[0] == 'n')
                    {
                        float thirdHeight  = (float)Math.Min(maxSizeHeight * 0.5f, Math.Round(position2.AspectRatio * _maxSizeWidth / (position3.AspectRatio + position2.AspectRatio)));
                        float secondHeight = maxSizeHeight - thirdHeight;
                        int   rightWidth   = (int)Math.Max(minWidth, Math.Min(_maxSizeWidth * 0.5f, Math.Round(Math.Min(thirdHeight * position3.AspectRatio, secondHeight * position2.AspectRatio))));

                        int leftWidth = (int)Math.Round(Math.Min(maxSizeHeight * position1.AspectRatio + paddingsWidth, _maxSizeWidth - rightWidth));
                        position1.Set(0, 0, 0, 1, leftWidth, 1.0f, POSITION_FLAG_LEFT | POSITION_FLAG_BOTTOM | POSITION_FLAG_TOP);

                        position2.Set(1, 1, 0, 0, rightWidth, secondHeight / maxSizeHeight, POSITION_FLAG_RIGHT | POSITION_FLAG_TOP);

                        position3.Set(0, 1, 1, 1, rightWidth, thirdHeight / maxSizeHeight, POSITION_FLAG_RIGHT | POSITION_FLAG_BOTTOM);
                        position3.SpanSize = _maxSizeWidth;

                        position1.SiblingHeights = new float[] { thirdHeight / maxSizeHeight, secondHeight / maxSizeHeight };

                        if (isOut)
                        {
                            position1.SpanSize = _maxSizeWidth - rightWidth;
                        }
                        else
                        {
                            position2.SpanSize       = _maxSizeWidth - leftWidth;
                            position3.LeftSpanOffset = leftWidth;
                        }
                        HasSibling = true;
                        maxX       = 1;

                        totalWidth  = leftWidth + rightWidth;
                        totalHeight = 1.0f;
                    }
                    else
                    {
                        float firstHeight = (float)Math.Round(Math.Min(_maxSizeWidth / position1.AspectRatio, (maxSizeHeight) * 0.66f)) / maxSizeHeight;
                        position1.Set(0, 1, 0, 0, _maxSizeWidth, firstHeight, POSITION_FLAG_LEFT | POSITION_FLAG_RIGHT | POSITION_FLAG_TOP);

                        int   width        = _maxSizeWidth / 2;
                        float secondHeight = (float)Math.Min(maxSizeHeight - firstHeight, Math.Round(Math.Min(width / position2.AspectRatio, width / position3.AspectRatio))) / maxSizeHeight;
                        position2.Set(0, 0, 1, 1, width, secondHeight, POSITION_FLAG_LEFT | POSITION_FLAG_BOTTOM);
                        position3.Set(1, 1, 1, 1, width, secondHeight, POSITION_FLAG_RIGHT | POSITION_FLAG_BOTTOM);
                        maxX = 1;

                        totalWidth  = _maxSizeWidth;
                        totalHeight = firstHeight + secondHeight;
                    }
                }
                else if (count == 4)
                {
                    GroupedMessagePosition position1 = _posArray[0];
                    GroupedMessagePosition position2 = _posArray[1];
                    GroupedMessagePosition position3 = _posArray[2];
                    GroupedMessagePosition position4 = _posArray[3];
                    if (proportions[0] == 'w')
                    {
                        float h0 = (float)Math.Round(Math.Min(_maxSizeWidth / position1.AspectRatio, maxSizeHeight * 0.66f)) / maxSizeHeight;
                        position1.Set(0, 2, 0, 0, _maxSizeWidth, h0, POSITION_FLAG_LEFT | POSITION_FLAG_RIGHT | POSITION_FLAG_TOP);

                        float h  = (float)Math.Round(_maxSizeWidth / (position2.AspectRatio + position3.AspectRatio + position4.AspectRatio));
                        int   w0 = (int)Math.Max(minWidth, Math.Min(_maxSizeWidth * 0.4f, h * position2.AspectRatio));
                        int   w2 = (int)Math.Max(Math.Max(minWidth, _maxSizeWidth * 0.33f), h * position4.AspectRatio);
                        int   w1 = _maxSizeWidth - w0 - w2;
                        h  = Math.Min(maxSizeHeight - h0, h);
                        h /= maxSizeHeight;
                        position2.Set(0, 0, 1, 1, w0, h, POSITION_FLAG_LEFT | POSITION_FLAG_BOTTOM);
                        position3.Set(1, 1, 1, 1, w1, h, POSITION_FLAG_BOTTOM);
                        position4.Set(2, 2, 1, 1, w2, h, POSITION_FLAG_RIGHT | POSITION_FLAG_BOTTOM);
                        maxX = 2;

                        totalWidth  = _maxSizeWidth;
                        totalHeight = h0 + h;
                    }
                    else
                    {
                        int   w  = (int)Math.Max(minWidth, Math.Round(maxSizeHeight / (1.0f / position2.AspectRatio + 1.0f / position3.AspectRatio + 1.0f / _posArray[3].AspectRatio)));
                        float h0 = Math.Min(0.33f, Math.Max(minHeight, w / position2.AspectRatio) / maxSizeHeight);
                        float h1 = Math.Min(0.33f, Math.Max(minHeight, w / position3.AspectRatio) / maxSizeHeight);
                        float h2 = 1.0f - h0 - h1;
                        int   w0 = (int)Math.Round(Math.Min(maxSizeHeight * position1.AspectRatio + paddingsWidth, _maxSizeWidth - w));

                        position1.Set(0, 0, 0, 2, w0, h0 + h1 + h2, POSITION_FLAG_LEFT | POSITION_FLAG_TOP | POSITION_FLAG_BOTTOM);

                        position2.Set(1, 1, 0, 0, w, h0, POSITION_FLAG_RIGHT | POSITION_FLAG_TOP);

                        position3.Set(0, 1, 1, 1, w, h1, POSITION_FLAG_RIGHT);
                        position3.SpanSize = _maxSizeWidth;

                        position4.Set(0, 1, 2, 2, w, h2, POSITION_FLAG_RIGHT | POSITION_FLAG_BOTTOM);
                        position4.SpanSize = _maxSizeWidth;

                        if (isOut)
                        {
                            position1.SpanSize = _maxSizeWidth - w;
                        }
                        else
                        {
                            position2.SpanSize       = _maxSizeWidth - w0;
                            position3.LeftSpanOffset = w0;
                            position4.LeftSpanOffset = w0;
                        }
                        position1.SiblingHeights = new float[] { h0, h1, h2 };
                        HasSibling = true;
                        maxX       = 1;

                        totalWidth  = w + w0;
                        totalHeight = h0 + h1 + h2;
                    }
                }
            }
            else
            {
                float[] croppedRatios = new float[_posArray.Count];
                for (int a = 0; a < count; a++)
                {
                    if (averageAspectRatio > 1.1f)
                    {
                        croppedRatios[a] = Math.Max(1.0f, _posArray[a].AspectRatio);
                    }
                    else
                    {
                        croppedRatios[a] = Math.Min(1.0f, _posArray[a].AspectRatio);
                    }
                    croppedRatios[a] = Math.Max(0.66667f, Math.Min(1.7f, croppedRatios[a]));
                }

                int firstLine;
                int secondLine;
                int thirdLine;
                int fourthLine;
                List <MessageGroupedLayoutAttempt> attempts = new List <MessageGroupedLayoutAttempt>();
                for (firstLine = 1; firstLine < croppedRatios.Length; firstLine++)
                {
                    secondLine = croppedRatios.Length - firstLine;
                    if (firstLine > 3 || secondLine > 3)
                    {
                        continue;
                    }
                    attempts.Add(new MessageGroupedLayoutAttempt(firstLine, secondLine, MultiHeight(croppedRatios, 0, firstLine), MultiHeight(croppedRatios, firstLine, croppedRatios.Length)));
                }

                for (firstLine = 1; firstLine < croppedRatios.Length - 1; firstLine++)
                {
                    for (secondLine = 1; secondLine < croppedRatios.Length - firstLine; secondLine++)
                    {
                        thirdLine = croppedRatios.Length - firstLine - secondLine;
                        if (firstLine > 3 || secondLine > (averageAspectRatio < 0.85f ? 4 : 3) || thirdLine > 3)
                        {
                            continue;
                        }
                        attempts.Add(new MessageGroupedLayoutAttempt(firstLine, secondLine, thirdLine, MultiHeight(croppedRatios, 0, firstLine), MultiHeight(croppedRatios, firstLine, firstLine + secondLine), MultiHeight(croppedRatios, firstLine + secondLine, croppedRatios.Length)));
                    }
                }

                for (firstLine = 1; firstLine < croppedRatios.Length - 2; firstLine++)
                {
                    for (secondLine = 1; secondLine < croppedRatios.Length - firstLine; secondLine++)
                    {
                        for (thirdLine = 1; thirdLine < croppedRatios.Length - firstLine - secondLine; thirdLine++)
                        {
                            fourthLine = croppedRatios.Length - firstLine - secondLine - thirdLine;
                            if (firstLine > 3 || secondLine > 3 || thirdLine > 3 || fourthLine > 3)
                            {
                                continue;
                            }
                            attempts.Add(new MessageGroupedLayoutAttempt(firstLine, secondLine, thirdLine, fourthLine, MultiHeight(croppedRatios, 0, firstLine), MultiHeight(croppedRatios, firstLine, firstLine + secondLine), MultiHeight(croppedRatios, firstLine + secondLine, firstLine + secondLine + thirdLine), MultiHeight(croppedRatios, firstLine + secondLine + thirdLine, croppedRatios.Length)));
                        }
                    }
                }

                MessageGroupedLayoutAttempt optimal = null;
                float optimalDiff = 0.0f;
                float maxHeight   = _maxSizeWidth / 3 * 4;
                for (int a = 0; a < attempts.Count; a++)
                {
                    MessageGroupedLayoutAttempt attempt = attempts[a];
                    float height        = 0;
                    float minLineHeight = float.MaxValue;
                    for (int b = 0; b < attempt.Heights.Length; b++)
                    {
                        height += attempt.Heights[b];
                        if (attempt.Heights[b] < minLineHeight)
                        {
                            minLineHeight = attempt.Heights[b];
                        }
                    }

                    float diff = Math.Abs(height - maxHeight);
                    if (attempt.LineCounts.Length > 1)
                    {
                        if (attempt.LineCounts[0] > attempt.LineCounts[1] || (attempt.LineCounts.Length > 2 && attempt.LineCounts[1] > attempt.LineCounts[2]) || (attempt.LineCounts.Length > 3 && attempt.LineCounts[2] > attempt.LineCounts[3]))
                        {
                            diff *= 1.5f;
                        }
                    }

                    if (minLineHeight < minWidth)
                    {
                        diff *= 1.5f;
                    }

                    if (optimal == null || diff < optimalDiff)
                    {
                        optimal     = attempt;
                        optimalDiff = diff;
                    }
                }
                if (optimal == null)
                {
                    return;
                }

                int   index = 0;
                float y     = 0.0f;

                for (int i = 0; i < optimal.LineCounts.Length; i++)
                {
                    int   c          = optimal.LineCounts[i];
                    float lineHeight = optimal.Heights[i];
                    int   spanLeft   = _maxSizeWidth;
                    GroupedMessagePosition posToFix = null;
                    maxX = Math.Max(maxX, c - 1);
                    for (int k = 0; k < c; k++)
                    {
                        float ratio = croppedRatios[index];
                        int   width = (int)(ratio * lineHeight);
                        spanLeft -= width;
                        GroupedMessagePosition pos = _posArray[index];
                        int flags = 0;
                        if (i == 0)
                        {
                            flags |= POSITION_FLAG_TOP;
                        }
                        if (i == optimal.LineCounts.Length - 1)
                        {
                            flags |= POSITION_FLAG_BOTTOM;
                        }
                        if (k == 0)
                        {
                            flags |= POSITION_FLAG_LEFT;
                            if (isOut)
                            {
                                posToFix = pos;
                            }
                        }
                        if (k == c - 1)
                        {
                            flags |= POSITION_FLAG_RIGHT;
                            if (!isOut)
                            {
                                posToFix = pos;
                            }
                        }
                        pos.Set(k, k, i, i, width, lineHeight / maxSizeHeight, flags);
                        index++;
                    }
                    posToFix.Width    += spanLeft;
                    posToFix.SpanSize += spanLeft;
                    y += lineHeight;
                }

                totalWidth  = _maxSizeWidth;
                totalHeight = y / maxSizeHeight;
            }
            int avatarOffset = 108;

            for (int a = 0; a < count; a++)
            {
                //GroupedMessagePosition pos = _posArray[a];
                //if (isOut)
                //{
                //    if (pos.MinX == 0)
                //    {
                //        pos.SpanSize += firstSpanAdditionalSize;
                //    }
                //    if ((pos.Flags & POSITION_FLAG_RIGHT) != 0)
                //    {
                //        pos.IsEdge = true;
                //    }
                //}
                //else
                //{
                //    if (pos.MaxX == maxX || (pos.Flags & POSITION_FLAG_RIGHT) != 0)
                //    {
                //        pos.SpanSize += firstSpanAdditionalSize;
                //    }
                //    if ((pos.Flags & POSITION_FLAG_LEFT) != 0)
                //    {
                //        pos.IsEdge = true;
                //    }
                //}
                //TLMessage messageObject = Messages[a];
                //if (!isOut && messageObject.needDrawAvatar())
                //{
                //    if (pos.IsEdge)
                //    {
                //        if (pos.SpanSize != 1000)
                //        {
                //            pos.SpanSize += avatarOffset;
                //        }
                //        pos.Width += avatarOffset;
                //    }
                //    else if ((pos.Flags & POSITION_FLAG_RIGHT) != 0)
                //    {
                //        if (pos.SpanSize != 1000)
                //        {
                //            pos.SpanSize -= avatarOffset;
                //        }
                //        else if (pos.LeftSpanOffset != 0)
                //        {
                //            pos.LeftSpanOffset += avatarOffset;
                //        }
                //    }
                //}
            }

            Width  = totalWidth;
            Height = totalHeight;
        }
예제 #2
0
        private void UpdatePhotoLayout(IMessageMediaGroup media)
        {
            if (LayoutRoot.Children.Count > 0)
            {
                _previousPanel = LayoutRoot.Children.FirstOrDefault() as StackPanel;
            }
            LayoutRoot.Children.Clear();

            if (media != null && media.GroupCommon != null && media.GroupCommon.Count > 0)
            {
                var groupedMessages = new GroupedMessages();
                foreach (var messageBase in media.GroupCommon)
                {
                    var message = messageBase as TLMessage;
                    if (message != null)
                    {
                        if (message.IsExpired())
                        {
                            continue;
                        }

                        groupedMessages.Messages.Add(message);
                    }
                    var decryptedMessage = messageBase as TLDecryptedMessage;
                    if (decryptedMessage != null)
                    {
                        //if (decryptedMessage.IsExpired())
                        //{
                        //    continue;
                        //}

                        groupedMessages.Messages.Add(decryptedMessage);
                    }
                }

                if (groupedMessages.Messages.Count == 0)
                {
                }
                else if (groupedMessages.Messages.Count == 1)
                {
                    var decryptedMessage = groupedMessages.Messages[0] as TLDecryptedMessage;
                    if (decryptedMessage != null)
                    {
                        var mediaPhoto = decryptedMessage.Media as TLDecryptedMessageMediaPhoto;
                        if (mediaPhoto != null)
                        {
                            var stackPanel = new StackPanel {
                                Background = new SolidColorBrush(Colors.Transparent)
                            };

                            var converter = new PhotoToDimensionConverter();
                            var width     = (double)converter.Convert(mediaPhoto, null, "Width", null);
                            var height    = (double)converter.Convert(mediaPhoto, null, "Height", null);

                            var groupedMessagePosition = new GroupedMessagePosition();
                            groupedMessagePosition.Set(0, 0, 0, 0, (int)width, 1.0f, 0);
                            var position = new KeyValuePair <TLObject, GroupedMessagePosition>(groupedMessages.Messages[0], groupedMessagePosition);

                            var border = GetControl(_previousPanel, position, 1.0, height, 0.0, 0.0);

                            stackPanel.Children.Add(border);

                            if (stackPanel.Children.Count > 0)
                            {
                                LayoutRoot.Children.Add(stackPanel);
                            }
                        }

                        if (decryptedMessage.IsVideo())
                        {
                            var stackPanel = new StackPanel {
                                Background = new SolidColorBrush(Colors.Transparent)
                            };

                            var width  = 230.0;
                            var height = 145.0;

                            var groupedMessagePosition = new GroupedMessagePosition();
                            groupedMessagePosition.Set(0, 0, 0, 0, (int)width, 1.0f, 0);
                            var position = new KeyValuePair <TLObject, GroupedMessagePosition>(groupedMessages.Messages[0], groupedMessagePosition);

                            var border = GetControl(_previousPanel, position, 1.0, height, 0.0, 0.0);

                            stackPanel.Children.Add(border);

                            if (stackPanel.Children.Count > 0)
                            {
                                LayoutRoot.Children.Add(stackPanel);
                            }
                        }
                    }

                    var message = groupedMessages.Messages[0] as TLMessage;
                    if (message != null)
                    {
                        var mediaPhoto = message.Media as TLMessageMediaPhoto;
                        if (mediaPhoto != null)
                        {
                            var stackPanel = new StackPanel {
                                Background = new SolidColorBrush(Colors.Transparent)
                            };

                            var converter = new PhotoToDimensionConverter();
                            var width     = (double)converter.Convert(mediaPhoto, null, "Width", null);
                            var height    = (double)converter.Convert(mediaPhoto, null, "Height", null);

                            var groupedMessagePosition = new GroupedMessagePosition();
                            groupedMessagePosition.Set(0, 0, 0, 0, (int)width, 1.0f, 0);
                            var position = new KeyValuePair <TLObject, GroupedMessagePosition>(groupedMessages.Messages[0], groupedMessagePosition);

                            var border = GetControl(_previousPanel, position, 1.0, height, 0.0, 0.0);

                            stackPanel.Children.Add(border);

                            if (stackPanel.Children.Count > 0)
                            {
                                LayoutRoot.Children.Add(stackPanel);
                            }
                        }

                        var mediaDocument = message.Media as TLMessageMediaDocument;
                        if (mediaDocument != null)
                        {
                            var stackPanel = new StackPanel {
                                Background = new SolidColorBrush(Colors.Transparent)
                            };

                            var width  = 230.0;
                            var height = 145.0;

                            var groupedMessagePosition = new GroupedMessagePosition();
                            groupedMessagePosition.Set(0, 0, 0, 0, (int)width, 1.0f, 0);
                            var position = new KeyValuePair <TLObject, GroupedMessagePosition>(groupedMessages.Messages[0], groupedMessagePosition);

                            var border = GetControl(_previousPanel, position, 1.0, height, 0.0, 0.0);

                            stackPanel.Children.Add(border);

                            if (stackPanel.Children.Count > 0)
                            {
                                LayoutRoot.Children.Add(stackPanel);
                            }
                        }
                    }
                }
                else if (groupedMessages.Messages.Count > 0)
                {
                    var height = 320;
                    groupedMessages.Calculate(height);

                    var stackPanel = new StackPanel {
                        Background = new SolidColorBrush(Colors.Transparent)
                    };

                    var positions = groupedMessages.Positions.ToList();

                    for (var i = 0; i < positions.Count; i++)
                    {
                        var position = positions[i];

                        var top  = 0.0;
                        var left = 0.0;

                        if (i > 0)
                        {
                            var pos = positions[i - 1];
                            // in one row
                            if (pos.Value.MinY == position.Value.MinY)
                            {
                                top = -(height * pos.Value.Height);

                                for (var j = i - 1; j >= 0; j--)
                                {
                                    pos = positions[j];
                                    if (pos.Value.MinY == position.Value.MinY)
                                    {
                                        left += pos.Value.Width;
                                    }
                                }
                            }
                            // in one column
                            else if (position.Value.SpanSize == groupedMessages.MaxSizeWidth)
                            {
                                left = position.Value.LeftSpanOffset;
                                // find common big message
                                KeyValuePair <TLObject, GroupedMessagePosition>?leftColumn = null;
                                for (var j = i - 1; j >= 0; j--)
                                {
                                    pos = positions[j];
                                    if (pos.Value.SiblingHeights != null)
                                    {
                                        leftColumn = pos;
                                        break;
                                    }
                                    else
                                    {
                                        top += (height * pos.Value.Height);
                                    }
                                }
                                // set top
                                if (leftColumn != null)
                                {
                                    top -= (leftColumn.Value.Value.Height * height);
                                }
                                else
                                {
                                    top = 0;
                                }
                            }
                        }

                        var border = GetControl(_previousPanel, position, 0.65, height, left, top);

                        stackPanel.Children.Add(border);
                    }

                    if (stackPanel.Children.Count > 0)
                    {
                        LayoutRoot.Children.Add(stackPanel);
                    }
                }
            }
        }