ViewSwitcher implementation (#1)
authorLukasz Stanislawski/IoT & UI Sample (PLT) /SRPOL/Engineer/Samsung Electronics <l.stanislaws@samsung.com>
Thu, 5 Mar 2020 14:55:27 +0000 (15:55 +0100)
committerGitHub Enterprise <noreply-CODE@samsung.com>
Thu, 5 Mar 2020 14:55:27 +0000 (15:55 +0100)
* Add ViewStack control

ViewStack control implements page-like based navigation in which
views are stacked over each other and only one, most recently added
child view is visible.

Oobe/Oobe/Controls/ViewStack.cs [new file with mode: 0644]
Oobe/Oobe/Oobe.cs
Oobe/Oobe/Oobe.csproj
Oobe/Oobe/Views/OobeViewSwitcher.cs [new file with mode: 0644]
Oobe/Oobe/Views/Page.cs [new file with mode: 0644]
Oobe/Oobe/res/0_BG_WHITEsmall.svg [new file with mode: 0644]
Oobe/Oobe/res/0_BG_dark.svg [new file with mode: 0644]

diff --git a/Oobe/Oobe/Controls/ViewStack.cs b/Oobe/Oobe/Controls/ViewStack.cs
new file mode 100644 (file)
index 0000000..549e323
--- /dev/null
@@ -0,0 +1,236 @@
+using System;
+using Tizen.NUI.Components;
+using Tizen.NUI.BaseComponents;
+using System.Collections.Generic;
+using Tizen.NUI;
+
+namespace Oobe.Controls
+{
+    /// <summary>
+    /// ViewStack implemenents stack based navigation in which all child views are stacked over each other
+    /// and only the most recent child added is visible.
+    /// </summary>
+    public class ViewStack : Control
+    {
+        private class ViewStackBaseCustomLayout : LayoutGroup
+        {
+            protected override void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
+            {
+                ViewStack stack = this.Owner as ViewStack;
+
+                if (!stack) return;
+
+                int totalWidth = stack.Size2D.Width;
+                int totalHeight = stack.Size2D.Height;
+
+                SetMeasuredDimensions(ResolveSizeAndState(new LayoutLength(totalWidth), widthMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK),
+                                      ResolveSizeAndState(new LayoutLength(totalHeight), heightMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK));
+            }
+
+            protected override void OnLayout(bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
+            {
+                ViewStack stack = this.Owner as ViewStack;
+
+                if (!changed || !stack) return;
+
+                int totalWidth = stack.Size2D.Width;
+                int totalHeight = stack.Size2D.Height;
+
+                foreach (LayoutItem childLayout in LayoutChildren)
+                {
+                    if (childLayout.Owner == stack.Current)
+                    {
+                        childLayout.Layout(
+                            new LayoutLength(0),
+                            new LayoutLength(0),
+                            new LayoutLength(totalWidth),
+                            new LayoutLength(totalHeight));
+                    } else
+                    {
+                        childLayout.Layout(
+                            new LayoutLength(- stack.PagesLeftPadding),
+                            new LayoutLength(0),
+                            new LayoutLength(totalWidth - stack.PagesLeftPadding),
+                            new LayoutLength(totalHeight));
+                    }
+                }
+            }
+        }
+
+        private List<View> views = new List<View>();
+        private List<View> viewsToRemove = new List<View>();
+
+        private Animation pageEnterAnimation;
+        private Animation pageLeaveAnimation;
+
+        /// <summary>
+        /// Informs about transition animation end
+        /// </summary>
+        public event EventHandler TransitionFinished;
+
+        /// <summary>
+        /// Number of pixels between stack right boundary and newly pushed child view left boundary,
+        /// which will be applied before starting page entering animation.
+        /// </summary>
+        /// <value></value>
+        public int PagesRightPadding { get; set; } = 0;
+
+        /// <summary>
+        /// Number of pixels between stack right boundary and current top child view left boundary,
+        /// which will be applied after finishing page leaving animation
+        /// </summary>
+        public int PagesLeftPadding { get; set; } = 0;
+
+        /// <summary>
+        /// Duration of page entering and page leaving animations
+        /// </summary>
+        public int ScrollDuration { get; set; } = 125;
+
+        /// <summary>
+        /// Get view currently stacked on Top of ViewStack
+        /// </summary>
+        public View Current { get { return views.Count > 0 ? views[views.Count-1] : null; } }
+
+        /// <summary>
+        /// Get view currently stacked under Current
+        /// </summary>
+        public View Previous { get { return views.Count > 1 ? views[views.Count - 2] : null; } }
+
+        public ViewStack() : base()
+        {
+            ClippingMode = ClippingModeType.ClipToBoundingBox;
+            Layout = new ViewStackBaseCustomLayout();
+            pageEnterAnimation = new Animation();
+            pageLeaveAnimation = new Animation();
+            pageEnterAnimation.Finished += OnPageEntered;
+            pageLeaveAnimation.Finished += OnPageLeave;
+        }
+
+        /// <summary>
+        /// Pop Current view with animation
+        /// </summary>
+        public void Pop()
+        {
+            if (Current != null)
+            {
+                FinishAnimations();
+                RemoveAllDelayedViews();
+                StartPageLeaveAnimation(Previous, Current);
+                AddViewToDelayRemove(Current);
+                views.Remove(Current);
+            }
+        }
+
+        /// <summary>
+        /// Pushed new view on stack with animation.
+        /// </summary>
+        public void Push(View view)
+        {
+            FinishAnimations();
+            RemoveAllDelayedViews();
+            Add(view);
+            StartPageEnterAnimation(Previous, Current);
+        }
+
+        public override void OnChildRemove(View view)
+        {
+            views.Remove(view);
+        }
+
+        public override void OnChildAdd(View view)
+        {
+            views.Add(view);
+        }
+
+        private void AddViewToDelayRemove(View view)
+        {
+            if (view)
+            {
+                viewsToRemove.Add(view);
+            }
+        }
+
+        private void RemoveAllDelayedViews()
+        {
+            foreach (View view in viewsToRemove)
+            {
+                // hide view to resolve issue with rendering artifacts
+                view.Hide();
+                Remove(view);
+            }
+            viewsToRemove.Clear();
+        }
+
+        private void FinishAnimations()
+        {
+            FinishAnimation(pageLeaveAnimation);
+            FinishAnimation(pageEnterAnimation);
+        }
+
+        static private void FinishAnimation(Animation anim)
+        {
+            if (anim != null)
+            {
+                if (anim.State == Animation.States.Playing)
+                {
+                    anim.Stop(Animation.EndActions.StopFinal);
+                }
+                anim.Clear();
+            }
+        }
+
+        private void StartPageLeaveAnimation(View back, View front)
+        {
+            pageLeaveAnimation.Duration = ScrollDuration;
+            pageLeaveAnimation.DefaultAlphaFunction = new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOutSine);
+
+            if (back != null)
+            {
+                // place 'back' out of viewport (should be already there)
+                // run animation to place 'back' in viewport
+                pageLeaveAnimation.AnimateTo(back, "PositionX", 0, null);
+            }
+            if (front != null)
+            {
+                // place 'front' in viewport (should be already there)
+                // run animation to place 'front' out of viewport
+                pageLeaveAnimation.AnimateTo(front, "PositionX", Size2D.Width + PagesRightPadding);
+            }
+            pageLeaveAnimation.Play();
+        }
+        private void StartPageEnterAnimation(View back, View front)
+        {
+            pageEnterAnimation.Duration = ScrollDuration;
+            pageEnterAnimation.DefaultAlphaFunction = new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOutSine);
+
+            if (back != null)
+            {
+                // place back in viewport (should be already there)
+                // run anim to place 'back' out of viewport
+                int diff = Position2D.X - PagesLeftPadding;
+                pageEnterAnimation.AnimateTo(back, "PositionX", diff);
+            }
+            if (front != null)
+            {
+                // place 'front' out of viewport
+                front.Position2D.X = Size2D.Width + PagesRightPadding;
+
+                // run anim to place 'front' on viewport
+                pageEnterAnimation.AnimateTo(front, "PositionX", 0, null);
+            }
+            pageEnterAnimation.Play();
+        }
+
+        private void OnPageEntered(object sender, EventArgs args)
+        {
+            TransitionFinished?.Invoke(this, new EventArgs());
+        }
+
+        private void OnPageLeave(object sender, EventArgs args)
+        {
+            RemoveAllDelayedViews();
+            TransitionFinished?.Invoke(this, new EventArgs());
+        }
+
+    }
+}
\ No newline at end of file
index 54dbe10..1c5899d 100644 (file)
@@ -1,37 +1,77 @@
 using System;
 using Tizen.NUI;
 using Tizen.NUI.BaseComponents;
-using Oobe.Language;
+using Tizen.NUI.Components;
+using Oobe.Controls;
+using Oobe.Views;
 
 namespace Oobe
 {
     class Program : NUIApplication
     {
+        private OobeViewSwitcher switcher;
+
         protected override void OnCreate()
         {
             base.OnCreate();
             Initialize();
         }
 
+        TextLabel makeLabel(string txt, Color color)
+        {
+            TextLabel text2 = new TextLabel(txt);
+            text2.HorizontalAlignment = HorizontalAlignment.Center;
+            text2.VerticalAlignment = VerticalAlignment.Center;
+            text2.TextColor = Color.Black;
+            text2.PointSize = 12.0f;
+            text2.HeightResizePolicy = ResizePolicyType.FillToParent;
+            text2.WidthResizePolicy = ResizePolicyType.FillToParent;
+
+            return text2;
+        }
+
         void Initialize()
         {
             Window.Instance.KeyEvent += OnKeyEvent;
-            var test = new LanguageStep(null);
-
-            TextLabel text = new TextLabel("Hello Tizen NUI World");
-            text.HorizontalAlignment = HorizontalAlignment.Center;
-            text.VerticalAlignment = VerticalAlignment.Center;
-            text.TextColor = Color.Blue;
-            text.PointSize = 12.0f;
-            text.HeightResizePolicy = ResizePolicyType.FillToParent;
-            text.WidthResizePolicy = ResizePolicyType.FillToParent;
-            Window.Instance.GetDefaultLayer().Add(text);
-
-            Animation animation = new Animation(2000);
-            animation.AnimateTo(text, "Orientation", new Rotation(new Radian(new Degree(180.0f)), PositionAxis.X), 0, 500);
-            animation.AnimateTo(text, "Orientation", new Rotation(new Radian(new Degree(0.0f)), PositionAxis.X), 500, 1000);
-            animation.Looping = true;
-            animation.Play();
+
+            switcher = new OobeViewSwitcher(Window.Instance);
+
+            Button button = new Button();
+            button.Text = "Push";
+            button.BackgroundColor = Color.Blue;
+            button.Size2D = new Size2D(100, 80);
+            button.Position2D.X = 48;
+            button.Position2D.Y = 720;
+            button.ClickEvent += PushClicked;
+            Window.Instance.GetDefaultLayer().Add(button);
+            
+            button = new Button();
+            button.Text = "Pop";
+            button.Position2D = new Position2D(250, 720);
+            button.BackgroundColor = Color.White;
+            button.Size2D = new Size2D(100, 80);
+            button.ClickEvent += PopClicked;
+            Window.Instance.GetDefaultLayer().Add(button);
+
+        }
+        int current = 0;
+        public static Color[] PossibleColors = new Color[]{
+            Color.White,
+            Color.White,
+            Color.White
+        };
+
+        public void PushClicked(object sender, EventArgs args)
+        {
+            Tizen.Log.Debug("ViewStack", "Push");
+            TextLabel text = makeLabel("More text", PossibleColors[current++ % PossibleColors.Length]);
+            switcher.Push(text);
+        }
+
+        public void PopClicked(object sender, EventArgs args)
+        {
+            Tizen.Log.Debug("ViewStack", "Pop");
+            switcher.Pop();
         }
 
         public void OnKeyEvent(object sender, Window.KeyEventArgs e)
index ca55803..a0e31ca 100644 (file)
@@ -22,7 +22,7 @@
     <PackageReference Include="Tizen.NET" Version="8.0.0.15106">
       <ExcludeAssets>Runtime</ExcludeAssets>
     </PackageReference>
-    <PackageReference Include="Tizen.NET.Sdk" Version="1.0.1" />
+    <PackageReference Include="Tizen.NET.Sdk" Version="1.0.9" />
   </ItemGroup>
 
   <ItemGroup>
diff --git a/Oobe/Oobe/Views/OobeViewSwitcher.cs b/Oobe/Oobe/Views/OobeViewSwitcher.cs
new file mode 100644 (file)
index 0000000..a9b64c6
--- /dev/null
@@ -0,0 +1,95 @@
+using Tizen.NUI.BaseComponents;
+using Tizen.NUI;
+using Oobe.Controls;
+
+namespace Oobe.Views
+{
+    /// <summary>
+    /// Implementation of OOBE GUI Guideline for IoT Headed
+    /// </summary>
+    public class OobeViewSwitcher
+    {
+        private ViewStack stack;
+        private Animation dimEffectAnimation;
+        private const int TransitionTime = 750;
+
+        public OobeViewSwitcher(Window win)
+        {
+            View backImage = new View();
+            backImage.BackgroundImage = NUIApplication.Current.DirectoryInfo.Resource + "0_BG_dark.svg";
+            backImage.WidthResizePolicy = ResizePolicyType.FillToParent;
+            backImage.HeightResizePolicy = ResizePolicyType.FillToParent;
+
+            stack = new ViewStack();
+            stack.ScrollDuration = TransitionTime;
+            stack.Position2D = new Position2D(48 - 6, 48 - 6); // include shadow
+            stack.Size2D = new Size2D(1184 + 6 + 9, 624 + 6 + 9); // includes surrounding shadow
+            stack.PagesRightPadding = 48;
+            stack.PagesLeftPadding = (int)(0.5f * stack.Size2D.Width);
+            stack.ClippingMode = ClippingModeType.Disabled;
+            dimEffectAnimation = new Animation(TransitionTime);
+
+            win.GetDefaultLayer().Add(backImage);
+            win.GetDefaultLayer().Add(stack);
+        }
+
+        public void Push(View view)
+        {
+            FinishDimAnimation();
+
+            var newView = new Views.Page();
+            newView.HeightResizePolicy = ResizePolicyType.FillToParent;
+            newView.WidthResizePolicy = ResizePolicyType.FillToParent;
+            newView.Content = view;
+            newView.Overlay.Opacity = 0.0f;
+
+            if (stack.Current is Views.Page overlayedView)
+            {
+                StartDimAnimation(overlayedView);
+            }
+
+            stack.Push(newView);
+        }
+
+        public void Pop()
+        {
+            FinishDimAnimation();
+            if (stack.Previous is Views.Page previous)
+            {
+                StartUndimAnimation(previous);
+            }
+            if (stack.Current is Views.Page current)
+            {
+                StartDimAnimation(current);
+            }
+            stack.Pop();
+        }
+
+        private void StartDimAnimation(Views.Page view)
+        {
+            view.Overlay.Opacity = 0.0f;
+            view.Opacity = 1.0f;
+            dimEffectAnimation.AnimateTo(view.Overlay, "Opacity", 0.5f);
+            dimEffectAnimation.AnimateTo(view, "Opacity", 0.0f);
+            dimEffectAnimation.Play();
+        }
+
+        private void StartUndimAnimation(Views.Page view)
+        {
+            view.Overlay.Opacity = 0.5f;
+            view.Opacity = 0.0f;
+            dimEffectAnimation.AnimateTo(view.Overlay, "Opacity", 0.0f);
+            dimEffectAnimation.AnimateTo(view, "Opacity", 1.0f);
+            dimEffectAnimation.Play();
+        }
+
+        private void FinishDimAnimation()
+        {
+            if (dimEffectAnimation.State == Animation.States.Playing)
+            {
+                dimEffectAnimation.Stop(Animation.EndActions.StopFinal);
+            }
+            dimEffectAnimation.Clear();
+        }
+    }
+}
diff --git a/Oobe/Oobe/Views/Page.cs b/Oobe/Oobe/Views/Page.cs
new file mode 100644 (file)
index 0000000..ad840d1
--- /dev/null
@@ -0,0 +1,50 @@
+using Tizen.NUI.BaseComponents;
+using Tizen.NUI;
+using Tizen.NUI.Components;
+
+namespace Oobe.Views
+{
+    /// <summary>
+    /// Implementation of OOBE GUI guideline for Tizen IoT headed
+    /// </summary>
+    public class Page : View
+    {
+        private View content;
+        private View overlay;
+
+        public View Content
+         {
+            set
+            {
+                if (value == content)
+                    return;
+                if (value)
+                {
+                    Remove(content);
+                    Remove(overlay);
+                    value.HeightResizePolicy = ResizePolicyType.FillToParent;
+                    value.WidthResizePolicy = ResizePolicyType.FillToParent;
+                    Add(value);
+                    Add(overlay);
+                    content = value;
+                }
+            }
+            get {
+                return content;
+            }
+        }
+
+        public View Overlay { get => overlay; }
+
+        public Page()
+        {
+            BackgroundImage = NUIApplication.Current.DirectoryInfo.Resource + "0_BG_WHITEsmall.svg";
+            overlay = new View();
+            overlay.BackgroundColor = Color.Black;
+            overlay.Opacity = 0.5f;
+            overlay.HeightResizePolicy = ResizePolicyType.FillToParent;
+            overlay.WidthResizePolicy = ResizePolicyType.FillToParent;
+        }
+
+    }
+}
diff --git a/Oobe/Oobe/res/0_BG_WHITEsmall.svg b/Oobe/Oobe/res/0_BG_WHITEsmall.svg
new file mode 100644 (file)
index 0000000..44120e9
--- /dev/null
@@ -0,0 +1,16 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1199" height="639" viewBox="0 0 1199 639">\r
+  <defs>\r
+    <filter id="Rectangle_860" x="0" y="0" width="1199" height="639" filterUnits="userSpaceOnUse">\r
+      <feOffset dx="1" dy="1" input="SourceAlpha"/>\r
+      <feGaussianBlur stdDeviation="2.5" result="blur"/>\r
+      <feFlood flood-opacity="0.161"/>\r
+      <feComposite operator="in" in2="blur"/>\r
+      <feComposite in="SourceGraphic"/>\r
+    </filter>\r
+  </defs>\r
+  <g id="_0_BG_WHITEsmall" data-name="0_BG_WHITEsmall" transform="translate(6.5 6.5)">\r
+    <g transform="matrix(1, 0, 0, 1, -6.5, -6.5)" filter="url(#Rectangle_860)">\r
+      <rect id="Rectangle_860-2" data-name="Rectangle 860" width="1184" height="624" rx="16" transform="translate(6.5 6.5)" fill="#fff" opacity="0.95"/>\r
+    </g>\r
+  </g>\r
+</svg>\r
diff --git a/Oobe/Oobe/res/0_BG_dark.svg b/Oobe/Oobe/res/0_BG_dark.svg
new file mode 100644 (file)
index 0000000..8d19b00
--- /dev/null
@@ -0,0 +1,42 @@
+<svg id="_0_BG_dark" data-name="0_BG_dark" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1280" height="720" viewBox="0 0 1280 720">\r
+  <defs>\r
+    <clipPath id="clip-path">\r
+      <rect id="Rectangle_876" data-name="Rectangle 876" width="1280" height="720" fill="none"/>\r
+    </clipPath>\r
+    <linearGradient id="linear-gradient" x1="0.164" y1="-0.433" x2="1.021" y2="-0.433" gradientUnits="objectBoundingBox">\r
+      <stop offset="0" stop-color="#052759"/>\r
+      <stop offset="1" stop-color="#a4b7d6"/>\r
+    </linearGradient>\r
+    <linearGradient id="linear-gradient-2" x1="-2.829" y1="-2.482" x2="-1.972" y2="-2.482" gradientUnits="objectBoundingBox">\r
+      <stop offset="0" stop-color="#00737f"/>\r
+      <stop offset="0.126" stop-color="#80a8b2"/>\r
+      <stop offset="0.351" stop-color="#1e6fa6"/>\r
+      <stop offset="1" stop-color="#5068e8"/>\r
+    </linearGradient>\r
+    <linearGradient id="linear-gradient-3" x1="0.152" y1="-5.005" x2="0.895" y2="-5.005" gradientUnits="objectBoundingBox">\r
+      <stop offset="0" stop-color="#ef34a4"/>\r
+      <stop offset="1" stop-color="#051a46"/>\r
+    </linearGradient>\r
+    <linearGradient id="linear-gradient-5" x1="-0.438" y1="2.176" x2="0.081" y2="2.176" gradientUnits="objectBoundingBox">\r
+      <stop offset="0" stop-color="#e682be"/>\r
+      <stop offset="1" stop-color="#24468d"/>\r
+    </linearGradient>\r
+    <linearGradient id="linear-gradient-6" x1="-1.354" y1="-3.765" x2="-0.473" y2="-3.765" gradientUnits="objectBoundingBox">\r
+      <stop offset="0" stop-color="#07458b"/>\r
+      <stop offset="1" stop-color="#2bcb4b"/>\r
+    </linearGradient>\r
+  </defs>\r
+  <rect id="Rectangle_860" data-name="Rectangle 860" width="1278" height="720" transform="translate(2)" fill="#fff"/>\r
+  <g id="Group_2" data-name="Group 2" clip-path="url(#clip-path)">\r
+    <g id="Group_511" data-name="Group 511" transform="translate(-188.33 -193.578)">\r
+      <path id="Rectangle_860-2" data-name="Rectangle 860" d="M0,0H1280V720H0Z" transform="translate(188.322 193.567)" fill="#172061"/>\r
+      <path id="Path_238" data-name="Path 238" d="M57.869-.015l352.173-.3a57.749,57.749,0,0,1,57.814,57.824h0a57.99,57.99,0,0,1-57.914,57.924l-352.172.3A57.749,57.749,0,0,1-.045,57.91h0A57.99,57.99,0,0,1,57.869-.015Z" transform="translate(923.638 108.552) rotate(138)" opacity="0.5" fill="url(#linear-gradient)"/>\r
+      <path id="Path_239" data-name="Path 239" d="M57.869-.015l352.172-.3a57.749,57.749,0,0,1,57.814,57.825h0a57.99,57.99,0,0,1-57.914,57.924l-352.172.3A57.749,57.749,0,0,1-.045,57.91h0A57.99,57.99,0,0,1,57.869-.015Z" transform="translate(1608.571 696.239) rotate(138.039)" fill="url(#linear-gradient-2)"/>\r
+      <path id="Path_240" data-name="Path 240" d="M57.862-.02,340.828-.259a57.882,57.882,0,0,1-.1,115.763l-282.966.238A57.882,57.882,0,0,1,57.862-.02Z" transform="translate(385.194 815.83) rotate(142)" opacity="0.6" fill="url(#linear-gradient-3)"/>\r
+      <path id="Path_241" data-name="Path 241" d="M57.874-.021,340.9-.267a57.869,57.869,0,0,1-.1,115.739l-283.026.246a57.869,57.869,0,1,1,.1-115.739Z" transform="translate(1687.259 224.683) rotate(135)" opacity="0.6" fill="url(#linear-gradient-3)"/>\r
+      <path id="Path_242" data-name="Path 242" d="M57.869-.014,417.663-.325A57.749,57.749,0,0,1,475.476,57.5h0a57.99,57.99,0,0,1-57.914,57.924l-359.793.311A57.749,57.749,0,0,1-.045,57.911h0A57.99,57.99,0,0,1,57.869-.014Z" transform="translate(482.093 280.677) rotate(138.039)" fill="#99a5e6" opacity="0.9"/>\r
+      <path id="Path_243" data-name="Path 243" d="M57.871-.021l278.44-.241A57.749,57.749,0,0,1,394.127,57.56h0a57.99,57.99,0,0,1-57.916,57.923l-278.441.241A57.749,57.749,0,0,1-.045,57.9h0A57.99,57.99,0,0,1,57.871-.021Z" transform="translate(1455.802 84.73) rotate(137)" fill="url(#linear-gradient-5)"/>\r
+      <path id="Path_244" data-name="Path 244" d="M57.858-.027l194.9-.161a57.754,57.754,0,0,1,57.806,57.837h0a57.985,57.985,0,0,1-57.9,57.933l-194.9.161A57.754,57.754,0,0,1-.043,57.906h0A57.985,57.985,0,0,1,57.858-.027Z" transform="matrix(0.81, -0.587, 0.587, 0.81, 534.439, 965.677)" opacity="0.21" fill="url(#linear-gradient-6)"/>\r
+    </g>\r
+  </g>\r
+</svg>\r