aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.FileSystem/Network/ChunkUploadRequest.cs
blob: ed6b3e45fad9e3f42c55ea3726e1abb4288fc6fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Tango.FileSystem.Network
{
    public class ChunkUploadRequest
    {
        public String OperationId { get; set; }
        public byte[] Data { get; set; }
        public bool IsCompleted { get; set; }
    }
}
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms.Integration;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Threading;
using Tango.Core;
using Tango.SharedUI.Helpers;

namespace Tango.SharedUI.Controls
{
    [ContentProperty(nameof(Elements))]
    public class NavigationControl : UserControl
    {
        private event Action NavigationCompleted;
        public event EventHandler<FrameworkElement> SelectedElementChanged;
        private Thread _navigationThread;
        private bool _preventSelectedObjectNavigation;
        private ProducerConsumerQueue<NavigationQueueItem> _navigationQueue;

        private class NavigationQueueItem
        {
            public NavigationElement FromElement { get; set; }
            public NavigationElement ToElement { get; set; }
        }

        #region Transition Types

        public enum TransitionTypes
        {
            Fade,
            Zoom,
            Slide,
        }

        #endregion

        #region Navigation Element

        private class NavigationElement : ContentControl
        {
            public FrameworkElement Element
            {
                get { return (FrameworkElement)GetValue(ElementProperty); }
                set { SetValue(ElementProperty, value); }
            }
            public static readonly DependencyProperty ElementProperty =
                DependencyProperty.Register("Element", typeof(FrameworkElement), typeof(NavigationControl), new PropertyMetadata(null));

            public ScaleTransform Scale
            {
                get { return (ScaleTransform)GetValue(ScaleProperty); }
                set { SetValue(ScaleProperty, value); }
            }
            public static readonly DependencyProperty ScaleProperty =
                DependencyProperty.Register("Scale", typeof(ScaleTransform), typeof(NavigationControl), new PropertyMetadata(null));

            public RotateTransform Rotate
            {
                get { return (RotateTransform)GetValue(RotateProperty); }
                set { SetValue(RotateProperty, value); }
            }
            public static readonly DependencyProperty RotateProperty =
                DependencyProperty.Register("Rotate", typeof(RotateTransform), typeof(NavigationControl), new PropertyMetadata(null));

            public TranslateTransform Translate
            {
                get { return (TranslateTransform)GetValue(TranslateProperty); }
                set { SetValue(TranslateProperty, value); }
            }
            public static readonly DependencyProperty TranslateProperty =
                DependencyProperty.Register("Translate", typeof(TranslateTransform), typeof(NavigationControl), new PropertyMetadata(null));

            public NavigationElement()
            {
                Visibility = Visibility.Hidden;

                Scale = new ScaleTransform(1, 1);
                Rotate = new RotateTransform(0);
                Translate = new TranslateTransform(0, 0);

                TransformGroup group = new TransformGroup();
                group.Children.Add(Scale);
                group.Children.Add(Rotate);
                group.Children.Add(Translate);

                RenderTransformOrigin = new Point(0.5, 0.5);
                RenderTransform = group;
            }

            public NavigationElement(FrameworkElement element) : this()
            {
                Element = element;
            }

            public void AnimateScale(DoubleAnimation animation)
            {
                Scale.BeginAnimation(ScaleTransform.ScaleXProperty, animation);
                Scale.BeginAnimation(ScaleTransform.ScaleYProperty, animation);
            }

            public void AnimateTranslateX(DoubleAnimation animation)
            {
                Translate.BeginAnimation(TranslateTransform.XProperty, animation);
            }

            public void AnimateOpacity(DoubleAnimation animation)
            {
                BeginAnimation(OpacityProperty, animation);
            }

            public void Reset()
            {
                Scale.BeginAnimation(ScaleTransform.ScaleXProperty, null);
                Scale.BeginAnimation(ScaleTransform.ScaleYProperty, null);
                Rotate.BeginAnimation(RotateTransform.AngleProperty, null);
                Translate.BeginAnimation(TranslateTransform.XProperty, null);
                Translate.BeginAnimation(TranslateTransform.YProperty, null);
                Opacity = 1;
            }

            public void Activate()
            {
                if (Content != Element)
                {
                    Content = Element;
                }

                Visibility = Visibility.Visible;
            }

            public void Deactivate(bool detach)
            {
                if (detach)
                {
                    Content = null;
                }

                Visibility = Visibility.Hidden;
            }
        }

        #endregion

        #region INavigationView

        public interface INavigationView
        {
            void OnNavigatedTo();
            void OnNavigatedFrom();
        }

        #endregion

        #region INavigationViewModel

        /// <summary>
        /// Represents a view data context which can be notified when its view is being navigated in or out.
        /// </summary>
        public interface INavigationViewModel
        {
            /// <summary>
            /// Called when the navigation system has navigated to this VM view.
            /// </summary>
            void OnNavigatedTo();

            /// <summary>
            /// Called when the navigation system has navigated from this VM view.
            /// </summary>
            void OnNavigatedFrom();
        }

        #endregion

        private Grid _grid;
        private bool _loaded;

        #region Properties



        public object SelectedObject
        {
            get { return (object)GetValue(SelectedObjectProperty); }
            set { SetValue(SelectedObjectProperty, value); }
        }
        public static readonly DependencyProperty SelectedObjectProperty =
            DependencyProperty.Register("SelectedObject", typeof(object), typeof(NavigationControl), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, (d, e) => (d as NavigationControl).OnSelectedObjectChanged()));

        private void OnSelectedObjectChanged()
        {
            if (SelectedObject != null && !_preventSelectedObjectNavigation)
            {
                NavigateTo(SelectedObject);
            }
        }

        public ObservableCollection<FrameworkElement> Elements
        {
            get { return (ObservableCollection<FrameworkElement>)GetValue(ElementsProperty); }
            set { SetValue(ElementsProperty, value); }
        }
        public static readonly DependencyProperty ElementsProperty =
            DependencyProperty.Register("Elements", typeof(ObservableCollection<FrameworkElement>), typeof(NavigationControl), new PropertyMetadata(null, (d, e) => (d as NavigationControl).OnElementsChanged()));

        public FrameworkElement SelectedElement
        {
            get { return (FrameworkElement)GetValue(SelectedElementProperty); }
            set { SetValue(SelectedElementProperty, value); }
        }
        public static readonly DependencyProperty SelectedElementProperty =
            DependencyProperty.Register("SelectedElement", typeof(FrameworkElement), typeof(NavigationControl), new FrameworkPropertyMetadata(null, (d, e) => (d as NavigationControl).OnSelectedElementChanged(e.OldValue as FrameworkElement, e.NewValue as FrameworkElement)));

        public TransitionTypes TransitionType
        {
            get { return (TransitionTypes)GetValue(TransitionTypeProperty); }
            set { SetValue(TransitionTypeProperty, value); }
        }
        public static readonly DependencyProperty TransitionTypeProperty =
            DependencyProperty.Register("TransitionType", typeof(TransitionTypes), typeof(NavigationControl), new PropertyMetadata(TransitionTypes.Zoom));

        public bool TransitionAlwaysFades
        {
            get { return (bool)GetValue(TransitionAlwaysFadesProperty); }
            set { SetValue(TransitionAlwaysFadesProperty, value); }
        }
        public static readonly DependencyProperty TransitionAlwaysFadesProperty =
            DependencyProperty.Register("TransitionAlwaysFades", typeof(bool), typeof(NavigationControl), new PropertyMetadata(false));

        public Duration TransitionDuration
        {
            get { return (Duration)GetValue(TransitionDurationProperty); }
            set { SetValue(TransitionDurationProperty, value); }
        }
        public static readonly DependencyProperty TransitionDurationProperty =
            DependencyProperty.Register("TransitionDuration", typeof(Duration), typeof(NavigationControl), new PropertyMetadata(new Duration(TimeSpan.FromSeconds(0.5))));

        public bool KeepElementsAttached
        {
            get { return (bool)GetValue(KeepElementsAttachedProperty); }
            set { SetValue(KeepElementsAttachedProperty, value); }
        }
        public static readonly DependencyProperty KeepElementsAttachedProperty =
            DependencyProperty.Register("KeepElementsAttached", typeof(bool), typeof(NavigationControl), new PropertyMetadata(false));



        public int SelectedIndex
        {
            get { return (int)GetValue(SelectedIndexProperty); }
            set { SetValue(SelectedIndexProperty, value); }
        }

        // Using a DependencyProperty as the backing store for SelectedIndex.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SelectedIndexProperty =
            DependencyProperty.Register("SelectedIndex", typeof(int), typeof(NavigationControl), new PropertyMetadata(0, (d, e) => (d as NavigationControl).OnSelectedIndexChanged()));

        public bool UseDefferedRendering
        {
            get { return (bool)GetValue(UseDefferedRenderingProperty); }
            set { SetValue(UseDefferedRenderingProperty, value); }
        }
        public static readonly DependencyProperty UseDefferedRenderingProperty =
            DependencyProperty.Register("UseDefferedRendering", typeof(bool), typeof(NavigationControl), new PropertyMetadata(false));



        private void OnSelectedIndexChanged()
        {
            SelectedElement = Elements[SelectedIndex > Elements.Count - 1 ? 0 : SelectedIndex];
        }

        #endregion

        #region Attached Properties

        #region NavigationName

        /// <summary>
        /// Determines the element navigation name.
        /// </summary>
        public static readonly DependencyProperty NavigationName =
            DependencyProperty.RegisterAttached("NavigationName",
            typeof(String), typeof(NavigationControl),
            new FrameworkPropertyMetadata(""));

        /// <summary>
        /// Sets the name of the navigation.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="value">The value.</param>
        public static void SetNavigationName(FrameworkElement element, String value)
        {
            element.SetValue(NavigationName, value);
        }

        /// <summary>
        /// Gets the name of the navigation.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        public static String GetNavigationName(FrameworkElement element)
        {
            var name = element.GetValue(NavigationName).ToStringSafe();
            if (String.IsNullOrEmpty(name)) name = element.GetType().Name;
            return name;
        }

        #endregion

        #endregion

        #region Constructors

        public NavigationControl()
        {
            ClipToBounds = true;
            _grid = new Grid();
            Content = _grid;
            Elements = new ObservableCollection<FrameworkElement>();
            Loaded += NavigationControl_Loaded;

            _navigationQueue = new ProducerConsumerQueue<NavigationQueueItem>();
            _navigationThread = new Thread(NavigationThread);
            _navigationThread.IsBackground = true;
            _navigationThread.Start();
        }

        #endregion

        #region Event Handlers

        private void NavigationControl_Loaded(object sender, RoutedEventArgs e)
        {
            if (!_loaded)
            {
                _loaded = true;

                if (Elements != null)
                {
                    //foreach (var element in Elements.Where(x => x != SelectedElement))
                    //{
                    //    LoadVisual(element);
                    //}

                    SelectedElement = Elements.FirstOrDefault();
                }
            }
        }

        private void Elements_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            SyncElements();
        }

        #endregion

        #region Private Methods

        private void OnElementsChanged()
        {
            if (Elements != null)
            {
                Elements.CollectionChanged -= Elements_CollectionChanged;
                Elements.CollectionChanged += Elements_CollectionChanged;
            }

            SyncElements();
        }

        private void SyncElements()
        {
            if (Elements == null)
            {
                _grid.Children.Clear();
            }
            else
            {
                Elements.ToList().ForEach(x => x.FocusVisualStyle = null);

                var toRemove = _grid.Children.OfType<NavigationElement>().ToList().Where(x => !Elements.Contains(x.Element)).ToList();
                var toAdd = Elements.Where(x => !_grid.Children.OfType<NavigationElement>().Select(y => y.Element).ToList().Contains(x)).ToList();

                toRemove.ForEach(x => _grid.Children.Remove(x));

                if (UseDefferedRendering)
                {
                    foreach (var x in toAdd)
                    {
                        var navigationElement = new NavigationElement()
                        {
                            RenderTransformOrigin = new Point(0.5, 0.5),
                            Element = x,
                            Content = x,
                        };

                        _grid.Children.Add(navigationElement);

                        if (!KeepElementsAttached)
                        {
                            bool loaded = false;

                            navigationElement.Loaded += (_, __) =>
                            {
                                if (!loaded)
                                {
                                    if (x != SelectedElement)
                                    {
                                        loaded = true;
                                        navigationElement.Content = null;
                                    }
                                }
                            };
                        }
                    }
                }
                else
                {
                    toAdd.ForEach(x => _grid.Children.Add(
                    new NavigationElement()
                    {
                        RenderTransformOrigin = new Point(0.5, 0.5),
                        Element = x,
                        Content = KeepElementsAttached ? x : null,
                    }));
                }
            }

            if (!Elements.Contains(SelectedElement))
            {
                SelectedElement = null;
            }
        }

        private NavigationElement GetElementContainer(FrameworkElement element)
        {
            return _grid.Children.OfType<NavigationElement>().ToList().SingleOrDefault(x => x.Element == element);
        }

        private void Navigate(NavigationElement fromElement, NavigationElement toElement)
        {
            _navigationQueue.BlockEnqueue(new NavigationQueueItem()
            {
                FromElement = fromElement,
                ToElement = toElement,
            });
        }

        private void NavigationThread()
        {
            while (true)
            {
                var item = _navigationQueue.BlockDequeue();

                var navigationCompleted = false;

                NavigationElement fromElement = item.FromElement;
                NavigationElement toElement = item.ToElement;

                Dispatcher.BeginInvoke(new Action(() =>
                {
                    if (toElement == null || toElement == fromElement)
                    {
                        //navigationCompleted = true;
                        Debug.WriteLine("NavigationControl: THIS MIGHT CAUSE PROBLEMS !!");
                    }

                    if (fromElement != null)
                    {
                        DoubleAnimation toAnimation = new DoubleAnimation();
                        toAnimation.Duration = TransitionDuration;

                        DoubleAnimation fromAnimation = new DoubleAnimation();
                        fromAnimation.Duration = TransitionDuration;

                        int fromIndex = Elements.IndexOf(fromElement.Element);
                        int toIndex = Elements.IndexOf(toElement.Element);

                        fromElement.Reset();
                        toElement.Reset();

                        fromAnimation.Completed += (_, __) =>
                        {
                            fromElement.Deactivate(!KeepElementsAttached);
                        };

                        bool completed = false;

                        toAnimation.Completed += (_, __) =>
                        {
                            if (!completed)
                            {
                                completed = true;

                                INavigationView fromNavigationView = fromElement.Element as INavigationView;
                                INavigationView toNavigationView = toElement.Element as INavigationView;

                                if (fromNavigationView != null)
                                {
                                    fromNavigationView.OnNavigatedFrom();
                                }
                                if (toNavigationView != null)
                                {
                                    toNavigationView.OnNavigatedTo();
                                }

                                INavigationViewModel fromVM = fromElement.Element.DataContext as INavigationViewModel;
                                INavigationViewModel toVM = toElement.Element.DataContext as INavigationViewModel;

                                if (fromVM != null && fromVM != toVM) fromVM.OnNavigatedFrom();
                                if (toVM != null) toVM.OnNavigatedTo();

                                navigationCompleted = true;
                            }
                        };

                        switch (TransitionType)
                        {
                            case TransitionTypes.Fade:
                                fromAnimation.From = 1;
                                fromAnimation.To = 0;

                                toAnimation.From = 0;
                                toAnimation.To = 1;

                                fromElement.AnimateOpacity(fromAnimation);
                                toElement.AnimateOpacity(toAnimation);

                                break;
                            case TransitionTypes.Zoom:
                                fromAnimation.From = 1;
                                fromAnimation.To = 0;

                                toAnimation.From = 0;
                                toAnimation.To = 1;

                                fromElement.AnimateScale(fromAnimation);
                                toElement.AnimateScale(toAnimation);

                                break;
                            case TransitionTypes.Slide:

                                if (toIndex > fromIndex)
                                {
                                    fromAnimation.From = 0;
                                    fromAnimation.To = -ActualWidth;

                                    toAnimation.From = ActualWidth;
                                    toAnimation.To = 0;
                                }
                                else
                                {
                                    fromAnimation.From = 0;
                                    fromAnimation.To = ActualWidth;

                                    toAnimation.From = -ActualWidth;
                                    toAnimation.To = 0;
                                }

                                fromElement.AnimateTranslateX(fromAnimation);
                                toElement.AnimateTranslateX(toAnimation);

                                break;
                        }

                        if (TransitionAlwaysFades && TransitionType != TransitionTypes.Fade)
                        {
                            DoubleAnimation fromFadeAnimation = new DoubleAnimation();
                            fromFadeAnimation.From = 1;
                            fromFadeAnimation.To = 0;
                            fromFadeAnimation.Duration = TransitionDuration;

                            DoubleAnimation toFadeAnimation = new DoubleAnimation();
                            toFadeAnimation.From = 0;
                            toFadeAnimation.To = 1;
                            toFadeAnimation.Duration = TransitionDuration;

                            fromElement.AnimateOpacity(fromFadeAnimation);
                            toElement.AnimateOpacity(toFadeAnimation);
                        }

                        fromElement.Activate();
                        toElement.Activate();
                    }
                    else
                    {
                        toElement.Activate();
                        toElement.Reset();

                        INavigationViewModel toVM = toElement.Element.DataContext as INavigationViewModel;
                        if (toVM != null) toVM.OnNavigatedTo();

                        navigationCompleted = true;
                    }
                }));

                for (int i = 0; i < 30; i++)
                {
                    if (navigationCompleted)
                    {
                        break;
                    }
                    Thread.Sleep(100);
                }

                Dispatcher.BeginInvoke(new Action(() =>
                {
                    NavigationCompleted?.Invoke();
                }));
            }
        }

        #endregion

        #region Properties Changes

        protected virtual void OnSelectedElementChanged(FrameworkElement fromElement, FrameworkElement toElement)
        {
            Navigate(GetElementContainer(fromElement), GetElementContainer(toElement));
            SelectedElementChanged?.Invoke(this, toElement);

            if (toElement != null)
            {
                _preventSelectedObjectNavigation = true;
                SelectedObject = GetNavigationName(toElement);
                _preventSelectedObjectNavigation = false;
            }
        }

        #endregion

        #region Public Methods

        public void NavigateTo(FrameworkElement element)
        {
            var e = Elements.SingleOrDefault(x => x == element);

            if (e != null)
            {
                SelectedElement = element;
            }
        }

        public FrameworkElement NavigateTo(String navigationName)
        {
            return NavigateTo(navigationName, null);
        }

        public FrameworkElement NavigateTo(Object obj)
        {
            return NavigateTo(obj.ToString(), null);
        }

        public FrameworkElement NavigateTo(String navigationName, Action onCompleted = null)
        {
            Action completed = null;

            completed = () =>
            {
                try
                {
                    onCompleted?.Invoke();
                }
                catch { }
                NavigationCompleted -= completed;
            };

            NavigationCompleted += completed;

            var element = Elements.SingleOrDefault(x => GetNavigationName(x) == navigationName || x.GetType().Name == navigationName);

            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(10);

                Dispatcher.BeginInvoke(new Action(async () =>
                {
                    if (element != null)
                    {
                        if (SelectedElement == element)
                        {
                            await Task.Delay((int)TransitionDuration.TimeSpan.TotalMilliseconds * 2);
                            NavigationCompleted?.Invoke();
                        }
                        else
                        {
                            SelectedElement = element;
                        }
                    }
                }));
            });

            return element;
        }

        public Task<FrameworkElement> NavigateToAsync(String navigationName)
        {
            TaskCompletionSource<FrameworkElement> source = new TaskCompletionSource<FrameworkElement>();

            FrameworkElement view = null;

            view = NavigateTo(navigationName, () =>
            {
                source.SetResult(view);
            });

            return source.Task;
        }

        public FrameworkElement GetElement(String navigationName)
        {
            return Elements.SingleOrDefault(x => GetNavigationName(x) == navigationName || x.GetType().Name == navigationName);
        }

        public FrameworkElement GetAndDetach(String navigationName)
        {
            var element = Elements.SingleOrDefault(x => GetNavigationName(x) == navigationName);
            GetElementContainer(element).Deactivate(!KeepElementsAttached);
            return element;
        }

        public String GetSelectedElementNavigationName()
        {
            return GetNavigationName(SelectedElement);
        }

        /// <remarks>
        /// This method needs to be called in order for 
        //  the element to print visibly at the correct size.
        /// </remarks>
        private static void LoadVisual(FrameworkElement element)
        {
            if (element.Parent == null)
            {
                try
                {
                    System.Windows.Forms.UserControl controlContainer = new System.Windows.Forms.UserControl();
                    controlContainer.Width = 100;
                    controlContainer.Height = 100;
                    var host = new ElementHost() { Child = element, Dock = System.Windows.Forms.DockStyle.Fill };
                    controlContainer.Controls.Add(host);
                    IntPtr handle = controlContainer.Handle;
                    host.Child = null;
                    controlContainer.Dispose();
                }
                catch { }
            }
        }
        #endregion
    }
}