aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage
diff options
context:
space:
mode:
authorAvi Levkovich <avi@twine-s.com>2018-12-04 17:44:06 +0200
committerAvi Levkovich <avi@twine-s.com>2018-12-04 17:44:06 +0200
commite64abeba3fd00cf6111b698384650b0e2a530436 (patch)
tree9b44c7d5c160926e6bba548947547090f220b199 /Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage
parente5d8713b456d335c19402360f0ba3e8a6db2c31e (diff)
parent704146a52197741c1df351e48098b91ca69a2426 (diff)
downloadTango-e64abeba3fd00cf6111b698384650b0e2a530436.tar.gz
Tango-e64abeba3fd00cf6111b698384650b0e2a530436.zip
merge conflicts
Diffstat (limited to 'Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage')
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Converters/StorageItemToImageConverter.cs39
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Helpers/FileIconHelper.cs146
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Images/file.pngbin0 -> 1184 bytes
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Images/folder.pngbin0 -> 756 bytes
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Images/storage.pngbin0 -> 197032 bytes
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Models/StorageFileHandlerModel.cs26
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Models/StorageFileHandlerType.cs14
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Properties/AssemblyInfo.cs19
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Properties/Resources.Designer.cs62
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Properties/Resources.resx117
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Properties/Settings.Designer.cs30
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Properties/Settings.settings7
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/StorageModule.cs62
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Tango.MachineStudio.Storage.csproj148
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/ViewModelLocator.cs29
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/ViewModels/MainViewVM.cs404
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Views/MainView.xaml332
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Views/MainView.xaml.cs49
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/app.config51
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/packages.config6
20 files changed, 1541 insertions, 0 deletions
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Converters/StorageItemToImageConverter.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Converters/StorageItemToImageConverter.cs
new file mode 100644
index 000000000..e9d2c8c18
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Converters/StorageItemToImageConverter.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Data;
+using Tango.Integration.Storage;
+using Tango.SharedUI.Helpers;
+
+namespace Tango.MachineStudio.Storage.Converters
+{
+ public class StorageItemToImageConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ StorageItem item = value as StorageItem;
+
+ if (item != null)
+ {
+ if (item is StorageFolder)
+ {
+ return ResourceHelper.GetImageFromResources("Images/folder.png");
+ }
+ else
+ {
+ return Helpers.FileIconHelper.FindIconForFilename(item.Name, true);
+ }
+ }
+
+ return null;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Helpers/FileIconHelper.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Helpers/FileIconHelper.cs
new file mode 100644
index 000000000..47dab8e5e
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Helpers/FileIconHelper.cs
@@ -0,0 +1,146 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Windows;
+using System.Windows.Interop;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+
+namespace Tango.MachineStudio.Storage.Helpers
+{
+ public static class FileIconHelper
+ {
+ private static readonly Dictionary<string, ImageSource> _smallIconCache = new Dictionary<string, ImageSource>();
+ private static readonly Dictionary<string, ImageSource> _largeIconCache = new Dictionary<string, ImageSource>();
+ /// <summary>
+ /// Get an icon for a given filename
+ /// </summary>
+ /// <param name="fileName">any filename</param>
+ /// <param name="large">16x16 or 32x32 icon</param>
+ /// <returns>null if path is null, otherwise - an icon</returns>
+ public static ImageSource FindIconForFilename(string fileName, bool large)
+ {
+ var extension = Path.GetExtension(fileName);
+ if (extension == null)
+ return null;
+ var cache = large ? _largeIconCache : _smallIconCache;
+ ImageSource icon;
+ if (cache.TryGetValue(extension, out icon))
+ return icon;
+ icon = IconReader.GetFileIcon(fileName, large ? IconReader.IconSize.Large : IconReader.IconSize.Small, false).ToImageSource();
+ cache.Add(extension, icon);
+ return icon;
+ }
+ /// <summary>
+ /// http://stackoverflow.com/a/6580799/1943849
+ /// </summary>
+ static ImageSource ToImageSource(this Icon icon)
+ {
+ var imageSource = Imaging.CreateBitmapSourceFromHIcon(
+ icon.Handle,
+ Int32Rect.Empty,
+ BitmapSizeOptions.FromEmptyOptions());
+ return imageSource;
+ }
+ /// <summary>
+ /// Provides static methods to read system icons for both folders and files.
+ /// </summary>
+ /// <example>
+ /// <code>IconReader.GetFileIcon("c:\\general.xls");</code>
+ /// </example>
+ static class IconReader
+ {
+ /// <summary>
+ /// Options to specify the size of icons to return.
+ /// </summary>
+ public enum IconSize
+ {
+ /// <summary>
+ /// Specify large icon - 32 pixels by 32 pixels.
+ /// </summary>
+ Large = 0,
+ /// <summary>
+ /// Specify small icon - 16 pixels by 16 pixels.
+ /// </summary>
+ Small = 1
+ }
+ /// <summary>
+ /// Returns an icon for a given file - indicated by the name parameter.
+ /// </summary>
+ /// <param name="name">Pathname for file.</param>
+ /// <param name="size">Large or small</param>
+ /// <param name="linkOverlay">Whether to include the link icon</param>
+ /// <returns>System.Drawing.Icon</returns>
+ public static Icon GetFileIcon(string name, IconSize size, bool linkOverlay)
+ {
+ var shfi = new Shell32.Shfileinfo();
+ var flags = Shell32.ShgfiIcon | Shell32.ShgfiUsefileattributes;
+ if (linkOverlay) flags += Shell32.ShgfiLinkoverlay;
+ /* Check the size specified for return. */
+ if (IconSize.Small == size)
+ flags += Shell32.ShgfiSmallicon;
+ else
+ flags += Shell32.ShgfiLargeicon;
+ Shell32.SHGetFileInfo(name,
+ Shell32.FileAttributeNormal,
+ ref shfi,
+ (uint)Marshal.SizeOf(shfi),
+ flags);
+ // Copy (clone) the returned icon to a new object, thus allowing us to clean-up properly
+ var icon = (Icon)Icon.FromHandle(shfi.hIcon).Clone();
+ User32.DestroyIcon(shfi.hIcon); // Cleanup
+ return icon;
+ }
+ }
+ /// <summary>
+ /// Wraps necessary Shell32.dll structures and functions required to retrieve Icon Handles using SHGetFileInfo. Code
+ /// courtesy of MSDN Cold Rooster Consulting case study.
+ /// </summary>
+ static class Shell32
+ {
+ private const int MaxPath = 256;
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Shfileinfo
+ {
+ private const int Namesize = 80;
+ public readonly IntPtr hIcon;
+ private readonly int iIcon;
+ private readonly uint dwAttributes;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MaxPath)]
+ private readonly string szDisplayName;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = Namesize)]
+ private readonly string szTypeName;
+ };
+ public const uint ShgfiIcon = 0x000000100; // get icon
+ public const uint ShgfiLinkoverlay = 0x000008000; // put a link overlay on icon
+ public const uint ShgfiLargeicon = 0x000000000; // get large icon
+ public const uint ShgfiSmallicon = 0x000000001; // get small icon
+ public const uint ShgfiUsefileattributes = 0x000000010; // use passed dwFileAttribute
+ public const uint FileAttributeNormal = 0x00000080;
+ [DllImport("Shell32.dll")]
+ public static extern IntPtr SHGetFileInfo(
+ string pszPath,
+ uint dwFileAttributes,
+ ref Shfileinfo psfi,
+ uint cbFileInfo,
+ uint uFlags
+ );
+ }
+ /// <summary>
+ /// Wraps necessary functions imported from User32.dll. Code courtesy of MSDN Cold Rooster Consulting example.
+ /// </summary>
+ static class User32
+ {
+ /// <summary>
+ /// Provides access to function required to delete handle. This method is used internally
+ /// and is not required to be called separately.
+ /// </summary>
+ /// <param name="hIcon">Pointer to icon handle.</param>
+ /// <returns>N/A</returns>
+ [DllImport("User32.dll")]
+ public static extern int DestroyIcon(IntPtr hIcon);
+ }
+ }
+}
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Images/file.png b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Images/file.png
new file mode 100644
index 000000000..a8cf88667
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Images/file.png
Binary files differ
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Images/folder.png b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Images/folder.png
new file mode 100644
index 000000000..1d32e80bf
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Images/folder.png
Binary files differ
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Images/storage.png b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Images/storage.png
new file mode 100644
index 000000000..1037998f1
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Images/storage.png
Binary files differ
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Models/StorageFileHandlerModel.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Models/StorageFileHandlerModel.cs
new file mode 100644
index 000000000..764512e77
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Models/StorageFileHandlerModel.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Tango.Core;
+using Tango.Integration.Storage;
+
+namespace Tango.MachineStudio.Storage.Models
+{
+ public class StorageFileHandlerModel : ExtendedObject
+ {
+ public StorageFileHandler Handler { get; set; }
+
+ public StorageFileHandlerType Type { get; set; }
+
+ public String FilePath { get; set; }
+
+ public StorageFileHandlerModel(StorageFileHandler handler, String filePath, StorageFileHandlerType type)
+ {
+ FilePath = filePath;
+ Handler = handler;
+ Type = type;
+ }
+ }
+}
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Models/StorageFileHandlerType.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Models/StorageFileHandlerType.cs
new file mode 100644
index 000000000..548b0fc86
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Models/StorageFileHandlerType.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.MachineStudio.Storage.Models
+{
+ public enum StorageFileHandlerType
+ {
+ Download,
+ Upload
+ }
+}
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Properties/AssemblyInfo.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..e1da8d0cd
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Properties/AssemblyInfo.cs
@@ -0,0 +1,19 @@
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Windows;
+
+[assembly: AssemblyTitle("Tango - Machine Studio Storage Module")]
+[assembly: AssemblyVersion("1.0.0.1737")]
+
+[assembly: ComVisible(false)]
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Properties/Resources.Designer.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Properties/Resources.Designer.cs
new file mode 100644
index 000000000..bd2484734
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Properties/Resources.Designer.cs
@@ -0,0 +1,62 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Tango.MachineStudio.Storage.Properties {
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if ((resourceMan == null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Tango.MachineStudio.Storage.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Properties/Resources.resx b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Properties/Resources.resx
new file mode 100644
index 000000000..af7dbebba
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Properties/Resources.resx
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+</root> \ No newline at end of file
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Properties/Settings.Designer.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Properties/Settings.Designer.cs
new file mode 100644
index 000000000..4076f7f8e
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Properties/Settings.Designer.cs
@@ -0,0 +1,30 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Tango.MachineStudio.Storage.Properties
+{
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
+ {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default
+ {
+ get
+ {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Properties/Settings.settings b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Properties/Settings.settings
new file mode 100644
index 000000000..033d7a5e9
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Properties/Settings.settings
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
+ <Profiles>
+ <Profile Name="(Default)" />
+ </Profiles>
+ <Settings />
+</SettingsFile> \ No newline at end of file
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/StorageModule.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/StorageModule.cs
new file mode 100644
index 000000000..f5b278627
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/StorageModule.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Media.Imaging;
+using Tango.BL.Enumerations;
+using Tango.MachineStudio.Common;
+using Tango.MachineStudio.Storage.Views;
+using Tango.SharedUI.Helpers;
+
+namespace Tango.MachineStudio.Storage
+{
+ [StudioModule(16)]
+ public class StorageModule : StudioModuleBase
+ {
+ public override string Name
+ {
+ get
+ {
+ return "Machine Storage";
+ }
+ }
+
+ public override string Description
+ {
+ get
+ {
+ return "Manage the machine flash file system storage using an interactive explorer.";
+ }
+ }
+
+ public override BitmapSource Image
+ {
+ get
+ {
+ return ResourceHelper.GetImageFromResources("Images/storage.png");
+ }
+ }
+
+ public override Type MainViewType
+ {
+ get
+ {
+ return typeof(MainView);
+ }
+ }
+
+ public override Permissions Permission
+ {
+ get
+ {
+ return Permissions.RunMachineStorageModule;
+ }
+ }
+
+ public override void Dispose()
+ {
+
+ }
+ }
+}
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Tango.MachineStudio.Storage.csproj b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Tango.MachineStudio.Storage.csproj
new file mode 100644
index 000000000..bceaf7158
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Tango.MachineStudio.Storage.csproj
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{5991F6B5-EA4E-41E9-A4F6-7D3A50010FD6}</ProjectGuid>
+ <OutputType>library</OutputType>
+ <RootNamespace>Tango.MachineStudio.Storage</RootNamespace>
+ <AssemblyName>Tango.MachineStudio.Storage</AssemblyName>
+ <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <WarningLevel>4</WarningLevel>
+ <Deterministic>true</Deterministic>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\..\Build\Machine Studio\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\..\Build\Machine Studio\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="MahApps.Metro, Version=1.5.0.23, Culture=neutral, PublicKeyToken=f4fb5a3c4d1e5b4f, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\MahApps.Metro.1.5.0\lib\net45\MahApps.Metro.dll</HintPath>
+ </Reference>
+ <Reference Include="MaterialDesignColors, Version=1.1.2.0, Culture=neutral, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\MaterialDesignColors.1.1.2\lib\net45\MaterialDesignColors.dll</HintPath>
+ </Reference>
+ <Reference Include="MaterialDesignThemes.Wpf, Version=2.3.1.953, Culture=neutral, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\MaterialDesignThemes.2.3.1.953\lib\net45\MaterialDesignThemes.Wpf.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Drawing" />
+ <Reference Include="System.Windows.Interactivity, Version=4.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\MahApps.Metro.1.5.0\lib\net45\System.Windows.Interactivity.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Xml" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Xaml">
+ <RequiredTargetFramework>4.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="WindowsBase" />
+ <Reference Include="PresentationCore" />
+ <Reference Include="PresentationFramework" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\..\..\Versioning\GlobalVersionInfo.cs">
+ <Link>GlobalVersionInfo.cs</Link>
+ </Compile>
+ <Compile Include="Converters\StorageItemToImageConverter.cs" />
+ <Compile Include="Helpers\FileIconHelper.cs" />
+ <Compile Include="Models\StorageFileHandlerModel.cs" />
+ <Compile Include="Models\StorageFileHandlerType.cs" />
+ <Compile Include="StorageModule.cs" />
+ <Compile Include="ViewModelLocator.cs" />
+ <Compile Include="ViewModels\MainViewVM.cs" />
+ <Compile Include="Views\MainView.xaml.cs">
+ <DependentUpon>MainView.xaml</DependentUpon>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Properties\AssemblyInfo.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Properties\Resources.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTime>True</DesignTime>
+ <DependentUpon>Resources.resx</DependentUpon>
+ </Compile>
+ <Compile Include="Properties\Settings.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DependentUpon>Settings.settings</DependentUpon>
+ <DesignTimeSharedInput>True</DesignTimeSharedInput>
+ </Compile>
+ <EmbeddedResource Include="Properties\Resources.resx">
+ <Generator>ResXFileCodeGenerator</Generator>
+ <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+ </EmbeddedResource>
+ <None Include="app.config" />
+ <None Include="packages.config" />
+ <None Include="Properties\Settings.settings">
+ <Generator>SettingsSingleFileGenerator</Generator>
+ <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\Tango.BL\Tango.BL.csproj">
+ <Project>{f441feee-322a-4943-b566-110e12fd3b72}</Project>
+ <Name>Tango.BL</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Core\Tango.Core.csproj">
+ <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project>
+ <Name>Tango.Core</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Integration\Tango.Integration.csproj">
+ <Project>{4206ac58-3b57-4699-8835-90bf6db01a61}</Project>
+ <Name>Tango.Integration</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Logging\Tango.Logging.csproj">
+ <Project>{bc932dbd-7cdb-488c-99e4-f02cf441f55e}</Project>
+ <Name>Tango.Logging</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.SharedUI\Tango.SharedUI.csproj">
+ <Project>{8491d07b-c1f6-4b62-a412-41b9fd2d6538}</Project>
+ <Name>Tango.SharedUI</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Transport\Tango.Transport.csproj">
+ <Project>{74e700b0-1156-4126-be40-ee450d3c3026}</Project>
+ <Name>Tango.Transport</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.MachineStudio.Common\Tango.MachineStudio.Common.csproj">
+ <Project>{cb0b0aa2-bb24-4bca-a720-45e397684e12}</Project>
+ <Name>Tango.MachineStudio.Common</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Page Include="Views\MainView.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\file.png" />
+ <Resource Include="Images\folder.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\storage.png" />
+ </ItemGroup>
+ <ItemGroup />
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project> \ No newline at end of file
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/ViewModelLocator.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/ViewModelLocator.cs
new file mode 100644
index 000000000..858fa9209
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/ViewModelLocator.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Tango.Core.DI;
+using Tango.MachineStudio.Storage.ViewModels;
+
+namespace Tango.MachineStudio.Storage
+{
+ public static class ViewModelLocator
+ {
+ /// <summary>
+ /// Initializes a new instance of the ViewModelLocator class.
+ /// </summary>
+ static ViewModelLocator()
+ {
+ TangoIOC.Default.Register<MainViewVM>();
+ }
+
+ public static MainViewVM MainViewVM
+ {
+ get
+ {
+ return TangoIOC.Default.GetInstance<MainViewVM>();
+ }
+ }
+ }
+}
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/ViewModels/MainViewVM.cs
new file mode 100644
index 000000000..4db48c636
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/ViewModels/MainViewVM.cs
@@ -0,0 +1,404 @@
+using Microsoft.Win32;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Tango.Core.Commands;
+using Tango.Core.IO;
+using Tango.Integration.ExternalBridge;
+using Tango.Integration.Storage;
+using Tango.MachineStudio.Common;
+using Tango.MachineStudio.Common.FirmwareUpgrade;
+using Tango.MachineStudio.Common.Notifications;
+using Tango.MachineStudio.Common.StudioApplication;
+using Tango.MachineStudio.Storage.Models;
+
+namespace Tango.MachineStudio.Storage.ViewModels
+{
+ public class MainViewVM : StudioViewModel
+ {
+ public event EventHandler CurrentFolderChanged;
+
+ private IStudioApplicationManager _applicationManager;
+ private INotificationProvider _notification;
+ private IFirmwareUpgrader _firmwareUpgrader;
+ private bool _machine_operator_changed = true;
+
+ private StorageManager _storageManager;
+ public StorageManager StorageManager
+ {
+ get { return _storageManager; }
+ set { _storageManager = value; RaisePropertyChangedAuto(); }
+ }
+
+ private StorageItem _selectedStorageItem;
+ public StorageItem SelectedStorageItem
+ {
+ get { return _selectedStorageItem; }
+ set { _selectedStorageItem = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); }
+ }
+
+ private String _currentPath;
+ public String CurrentPath
+ {
+ get { return _currentPath; }
+ set { _currentPath = value; RaisePropertyChangedAuto(); }
+ }
+
+ public ObservableCollection<StorageFileHandlerModel> FileHandlers { get; set; }
+
+ public RelayCommand BackCommand { get; set; }
+
+ public RelayCommand RefreshCommand { get; set; }
+
+ public RelayCommand GoCommand { get; set; }
+
+ public RelayCommand<StorageFileHandlerModel> CancelFileHandlerCommand { get; set; }
+
+ public RelayCommand<StorageFileHandlerModel> OpenFileHandlerCommand { get; set; }
+
+ public RelayCommand<StorageFileHandlerModel> RemoveFileHandlerCommand { get; set; }
+
+ public RelayCommand DownloadFileCommand { get; set; }
+
+ public RelayCommand DeleteFileCommand { get; set; }
+
+ public RelayCommand CreateFolderCommand { get; set; }
+
+ public RelayCommand DeleteFolderCommand { get; set; }
+
+ public RelayCommand UploadFileCommand { get; set; }
+
+ public RelayCommand UploadVersionCommand { get; set; }
+
+ public RelayCommand ValidateVersionCommand { get; set; }
+
+ public RelayCommand ActivateVersionCommand { get; set; }
+
+ public MainViewVM(IStudioApplicationManager applicationManager, INotificationProvider notificationProvider, IFirmwareUpgrader firmwareUpgrader)
+ {
+ _applicationManager = applicationManager;
+ _notification = notificationProvider;
+ _firmwareUpgrader = firmwareUpgrader;
+ _applicationManager.ConnectedMachineChanged += _applicationManager_ConnectedMachineChanged;
+
+ FileHandlers = new ObservableCollection<StorageFileHandlerModel>();
+
+ GoCommand = new RelayCommand(() => NavigateToPath(CurrentPath), () => StorageManager != null);
+ BackCommand = new RelayCommand(NavigateBack, () => StorageManager != null && StorageManager.CurrentFolder.Parent != null);
+ CancelFileHandlerCommand = new RelayCommand<StorageFileHandlerModel>(CancelFileHandler);
+ OpenFileHandlerCommand = new RelayCommand<StorageFileHandlerModel>(OpenFileHandler);
+ RefreshCommand = new RelayCommand(Refresh, () => StorageManager != null);
+ RemoveFileHandlerCommand = new RelayCommand<StorageFileHandlerModel>(RemoveFileHandler);
+ DownloadFileCommand = new RelayCommand(DownloadFile, () => StorageManager != null && SelectedStorageItem != null && SelectedStorageItem is StorageFile);
+ DeleteFileCommand = new RelayCommand(DeleteFile, () => StorageManager != null && SelectedStorageItem != null && SelectedStorageItem is StorageFile);
+ CreateFolderCommand = new RelayCommand(CreateFolder, () => StorageManager != null && StorageManager.CurrentFolder != null);
+ DeleteFolderCommand = new RelayCommand(DeleteFolder, () => StorageManager != null && SelectedStorageItem != null && SelectedStorageItem is StorageFolder);
+ UploadFileCommand = new RelayCommand(UploadFile, () => StorageManager != null && StorageManager.CurrentFolder != null);
+ UploadVersionCommand = new RelayCommand(UploadVersion, () => StorageManager != null && StorageManager.CurrentFolder != null);
+ ValidateVersionCommand = new RelayCommand(ValidateVersion, () => StorageManager != null && StorageManager.CurrentFolder != null);
+ ActivateVersionCommand = new RelayCommand(ActivateVersion, () => StorageManager != null && StorageManager.CurrentFolder != null);
+ }
+
+ private void UploadFile()
+ {
+ OpenFileDialog dlg = new OpenFileDialog();
+ dlg.Title = "Selected a file to upload";
+ if (dlg.ShowDialog().Value)
+ {
+ UploadFile(dlg.FileName);
+ }
+ }
+
+ private async void DeleteFolder()
+ {
+ if (SelectedStorageItem == null) return;
+
+ if (_notification.ShowQuestion("Are you sure you want to delete the selected folder?"))
+ {
+ try
+ {
+ IsFree = false;
+ await StorageManager.DeleteItem(SelectedStorageItem);
+ Refresh();
+ }
+ catch (Exception ex)
+ {
+ _notification.ShowError($"Error deleting the selected folder.\n{ex.Message}");
+ }
+
+ IsFree = true;
+ }
+ }
+
+ private async void CreateFolder()
+ {
+ try
+ {
+ var name = _notification.ShowTextInput("Enter Folder Name", "");
+
+ if (!String.IsNullOrWhiteSpace(name))
+ {
+ IsFree = false;
+ await StorageManager.CreateFolder(Path.Combine(StorageManager.CurrentPath, name));
+ Refresh();
+ }
+ }
+ catch (Exception ex)
+ {
+ _notification.ShowError($"Error creating the new folder.\n{ex.Message}");
+ }
+
+ IsFree = true;
+ }
+
+ private async void DeleteFile()
+ {
+ if (SelectedStorageItem == null) return;
+
+ if (_notification.ShowQuestion("Are you sure you want to delete the selected file?"))
+ {
+ try
+ {
+ IsFree = false;
+ await StorageManager.DeleteItem(SelectedStorageItem);
+ Refresh();
+ }
+ catch (Exception ex)
+ {
+ _notification.ShowError($"Error deleting the selected file.\n{ex.Message}");
+ }
+
+ IsFree = true;
+ }
+ }
+
+ private void DownloadFile()
+ {
+ DownloadStorageItem(SelectedStorageItem as StorageFile);
+ }
+
+ private void OpenFileHandler(StorageFileHandlerModel handler)
+ {
+ ShowInExplorer(handler.FilePath);
+ }
+
+ private async void CancelFileHandler(StorageFileHandlerModel handler)
+ {
+ await handler.Handler.Cancel();
+ }
+
+ private void _applicationManager_ConnectedMachineChanged(object sender, IExternalBridgeClient e)
+ {
+ _machine_operator_changed = true;
+
+ if (IsVisible)
+ {
+ Initialize();
+ }
+ }
+
+ public override void OnApplicationReady()
+ {
+
+ }
+
+ public override void OnNavigatedTo()
+ {
+ base.OnNavigatedTo();
+
+ if (_machine_operator_changed)
+ {
+ _machine_operator_changed = false;
+ Initialize();
+ }
+ }
+
+ private async void NavigateToPath(String path, bool raiseEvent = true)
+ {
+ IsFree = false;
+
+ try
+ {
+ await StorageManager.GetFolder(path);
+ CurrentPath = StorageManager.CurrentPath;
+
+ if (raiseEvent)
+ {
+ CurrentFolderChanged?.Invoke(this, new EventArgs());
+ }
+ }
+ catch (Exception ex)
+ {
+ _notification.ShowError($"Error navigating to the specified path.\n{ex.Message}");
+ }
+
+ IsFree = true;
+
+ InvalidateRelayCommands();
+ }
+
+ private async void Initialize()
+ {
+ if (_applicationManager.ConnectedMachine != null)
+ {
+ try
+ {
+ StorageManager = _applicationManager.ConnectedMachine.CreateStorageManager();
+ await StorageManager.GetStorageDrive();
+ await StorageManager.GetRootFolder();
+ CurrentPath = StorageManager.StorageDrive.Root;
+ }
+ catch (Exception ex)
+ {
+ _notification.ShowError($"An error occurred while trying to initialize the storage manager.\n{ex.Message}");
+ }
+
+ InvalidateRelayCommands();
+ }
+ }
+
+ public void OnStorageItemDoubleClicked(StorageItem storageItem)
+ {
+ if (storageItem is StorageFolder && storageItem != null)
+ {
+ NavigateToPath(storageItem.Path);
+ }
+ else
+ {
+ DownloadStorageItem(storageItem as StorageFile);
+ }
+ }
+
+ private void NavigateBack()
+ {
+ NavigateToPath(StorageManager.CurrentFolder.Parent);
+ }
+
+ private void Refresh()
+ {
+ NavigateToPath(StorageManager.CurrentFolder.Path, false);
+ }
+
+ private async void DownloadStorageItem(StorageFile storageFile)
+ {
+ SaveFileDialog dlg = new SaveFileDialog();
+ dlg.Title = "Select download location";
+ dlg.DefaultExt = Path.GetExtension(storageFile.Path);
+ dlg.FileName = storageFile.Name;
+ if (dlg.ShowDialog().Value)
+ {
+ FileStream fs = new FileStream(dlg.FileName, FileMode.Create);
+ var handler = await StorageManager.DownloadFile(storageFile, fs);
+ handler.Completed += (_, __) =>
+ {
+ fs.Dispose();
+ };
+
+ handler.Canceled += (_, __) =>
+ {
+ fs.Dispose();
+ File.Delete(dlg.FileName);
+ };
+
+ handler.Failed += (_, __) =>
+ {
+ fs.Dispose();
+ File.Delete(dlg.FileName);
+ };
+
+ FileHandlers.Insert(0, new StorageFileHandlerModel(handler, dlg.FileName, StorageFileHandlerType.Download));
+ }
+ }
+
+ private async void UploadFile(String path)
+ {
+ FileStream fs = new FileStream(path, FileMode.Open);
+ var handler = await StorageManager.UploadFile(Path.Combine(StorageManager.CurrentPath, Path.GetFileName(path)), fs);
+ handler.Completed += (_, __) =>
+ {
+ fs.Dispose();
+ };
+
+ handler.Canceled += (_, __) =>
+ {
+ fs.Dispose();
+ File.Delete(path);
+ };
+
+ handler.Failed += (_, __) =>
+ {
+ fs.Dispose();
+ File.Delete(path);
+ };
+
+ FileHandlers.Insert(0, new StorageFileHandlerModel(handler, path, StorageFileHandlerType.Upload));
+ }
+
+ /// <summary>
+ /// Shows the file in explorer.
+ /// </summary>
+ /// <param name="path">Name of the file/folder.</param>
+ public static void ShowInExplorer(String path)
+ {
+ Process.Start("explorer.exe", string.Format("/select,\"{0}\"", path));
+ }
+
+ private void RemoveFileHandler(StorageFileHandlerModel handler)
+ {
+ if (handler.Handler.Status == StorageFileHandlerStatus.Active)
+ {
+ if (_notification.ShowQuestion("Are you sure you want to cancel this file operation?"))
+ {
+ handler.Handler.Cancel();
+ FileHandlers.Remove(handler);
+ }
+ }
+ else
+ {
+ FileHandlers.Remove(handler);
+ }
+ }
+
+ private void UploadVersion()
+ {
+ _firmwareUpgrader.InvokeUpgradeUI();
+ }
+
+ private async void ValidateVersion()
+ {
+ using (_notification.PushTaskItem("Validating firmware version..."))
+ {
+ try
+ {
+ await _applicationManager.ConnectedMachine.ValidateFirmwareVersion(StorageManager.CurrentPath);
+ _notification.ShowInfo($"Version validated successfully!");
+ }
+ catch (Exception ex)
+ {
+ _notification.ShowError($"Error validating firmware version.\n{ex.FlattenMessage()}");
+ }
+ }
+ }
+
+ private async void ActivateVersion()
+ {
+ using (_notification.PushTaskItem("Activating firmware version..."))
+ {
+ try
+ {
+ await _applicationManager.ConnectedMachine.ActivateFirmwareVersion(StorageManager.CurrentPath);
+ _notification.ShowInfo($"Version activated successfully!");
+ }
+ catch (Exception ex)
+ {
+ _notification.ShowError($"Error activating firmware version.\n{ex.FlattenMessage()}");
+ }
+ }
+ }
+ }
+}
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Views/MainView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Views/MainView.xaml
new file mode 100644
index 000000000..e59837d49
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Views/MainView.xaml
@@ -0,0 +1,332 @@
+<UserControl x:Class="Tango.MachineStudio.Storage.Views.MainView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:vm="clr-namespace:Tango.MachineStudio.Storage.ViewModels"
+ xmlns:global="clr-namespace:Tango.MachineStudio.Storage"
+ xmlns:mahApps="http://metro.mahapps.com/winfx/xaml/controls"
+ xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI"
+ xmlns:localConverters="clr-namespace:Tango.MachineStudio.Storage.Converters"
+ xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
+ xmlns:local="clr-namespace:Tango.MachineStudio.Storage.Views"
+ mc:Ignorable="d"
+ d:DesignHeight="1080" x:Name="control" d:DesignWidth="1920" Background="Transparent" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}">
+
+ <UserControl.Resources>
+ <localConverters:StorageItemToImageConverter x:Key="StorageItemToImageConverter" />
+ <converters:ByteArrayToFileSizeConverter x:Key="ByteArrayToFileSizeConverter" />
+ </UserControl.Resources>
+
+ <Grid>
+ <Grid>
+ <DockPanel>
+
+ <Border Background="#ECECEC" Margin="20" Width="350" CornerRadius="5" IsEnabled="{Binding IsFree}">
+ <Border.Effect>
+ <DropShadowEffect ShadowDepth="0" BlurRadius="10" Color="Gray" />
+ </Border.Effect>
+ <DockPanel>
+ <TextBlock HorizontalAlignment="Left" DockPanel.Dock="Top" Margin="30 55 20 20" FontSize="30" FontStyle="Italic" Foreground="{StaticResource AccentColorBrush}" FontWeight="Bold">ACTIONS</TextBlock>
+ <StackPanel Margin="0 40 0 0">
+ <Button Command="{Binding CreateFolderCommand}" Margin="0 5 0 0" Style="{StaticResource MaterialDesignFlatButton}" Padding="20 10" Height="Auto" Foreground="#363636" HorizontalContentAlignment="Left">
+ <DockPanel>
+ <materialDesign:PackIcon Kind="FolderPlus" Foreground="#E79F20" Width="32" Height="32" />
+ <TextBlock VerticalAlignment="Center" Margin="20 0 0 0" FontSize="18">CREATE FOLDER</TextBlock>
+ </DockPanel>
+ </Button>
+ <Button Command="{Binding DeleteFolderCommand}" Margin="0 5 0 0" Style="{StaticResource MaterialDesignFlatButton}" Padding="20 10" Height="Auto" Foreground="#363636" HorizontalContentAlignment="Left">
+ <DockPanel>
+ <materialDesign:PackIcon Kind="FolderRemove" Foreground="#E14141" Width="32" Height="32" />
+ <TextBlock VerticalAlignment="Center" Margin="20 0 0 0" FontSize="18">DELETE FOLDER</TextBlock>
+ </DockPanel>
+ </Button>
+ <Separator/>
+ <Button Command="{Binding UploadFileCommand}" Margin="0 5 0 0" Style="{StaticResource MaterialDesignFlatButton}" Padding="20 10" Height="Auto" Foreground="#363636" HorizontalContentAlignment="Left">
+ <DockPanel>
+ <materialDesign:PackIcon Kind="Upload" Foreground="#E97E28" Width="32" Height="32" />
+ <TextBlock VerticalAlignment="Center" Margin="20 0 0 0" FontSize="18">UPLOAD FILE</TextBlock>
+ </DockPanel>
+ </Button>
+ <Button Command="{Binding DownloadFileCommand}" Margin="0 5 0 0" Style="{StaticResource MaterialDesignFlatButton}" Padding="20 10" Height="Auto" Foreground="#363636" HorizontalContentAlignment="Left">
+ <DockPanel>
+ <materialDesign:PackIcon Kind="Download" Foreground="#2DD42D" Width="32" Height="32" />
+ <TextBlock VerticalAlignment="Center" Margin="20 0 0 0" FontSize="18">DOWNLOAD FILE</TextBlock>
+ </DockPanel>
+ </Button>
+ <Separator/>
+ <Button Command="{Binding DeleteFileCommand}" Margin="0 5 0 0" Style="{StaticResource MaterialDesignFlatButton}" Padding="20 10" Height="Auto" Foreground="#363636" HorizontalContentAlignment="Left">
+ <DockPanel>
+ <materialDesign:PackIcon Kind="Delete" Foreground="#E14141" Width="32" Height="32" />
+ <TextBlock VerticalAlignment="Center" Margin="20 0 0 0" FontSize="18">DELETE FILE</TextBlock>
+ </DockPanel>
+ </Button>
+ <Separator/>
+ <Button Command="{Binding UploadVersionCommand}" Margin="0 5 0 0" Style="{StaticResource MaterialDesignFlatButton}" Padding="20 10" Height="Auto" Foreground="#363636" HorizontalContentAlignment="Left">
+ <DockPanel>
+ <materialDesign:PackIcon Kind="BriefcaseUpload" Foreground="#833CEC" Width="32" Height="32" />
+ <TextBlock VerticalAlignment="Center" Margin="20 0 0 0" FontSize="18">UPGRADE VERSION</TextBlock>
+ </DockPanel>
+ </Button>
+ <Button Command="{Binding ValidateVersionCommand}" Margin="0 5 0 0" Style="{StaticResource MaterialDesignFlatButton}" Padding="20 10" Height="Auto" Foreground="#363636" HorizontalContentAlignment="Left">
+ <DockPanel>
+ <materialDesign:PackIcon Kind="CheckAll" Foreground="#682EBE" Width="32" Height="32" />
+ <TextBlock VerticalAlignment="Center" Margin="20 0 0 0" FontSize="18">VALIDATE VERSION</TextBlock>
+ </DockPanel>
+ </Button>
+ <Button Command="{Binding ActivateVersionCommand}" Margin="0 5 0 0" Style="{StaticResource MaterialDesignFlatButton}" Padding="20 10" Height="Auto" Foreground="#363636" HorizontalContentAlignment="Left">
+ <DockPanel>
+ <materialDesign:PackIcon Kind="Flash" Foreground="#532990" Width="32" Height="32" />
+ <TextBlock VerticalAlignment="Center" Margin="20 0 0 0" FontSize="18">ACTIVATE VERSION</TextBlock>
+ </DockPanel>
+ </Button>
+ <Separator/>
+ <Button Command="{Binding RefreshCommand}" Margin="0 5 0 0" Style="{StaticResource MaterialDesignFlatButton}" Padding="20 10" Height="Auto" Foreground="#363636" HorizontalContentAlignment="Left">
+ <DockPanel>
+ <materialDesign:PackIcon Kind="Refresh" Foreground="{StaticResource AccentColorBrush}" Width="32" Height="32" />
+ <TextBlock VerticalAlignment="Center" Margin="20 0 0 0" FontSize="18">REFRESH</TextBlock>
+ </DockPanel>
+ </Button>
+ </StackPanel>
+ </DockPanel>
+ </Border>
+
+ <Grid>
+ <DockPanel>
+ <Border DockPanel.Dock="Top" Background="#ECECEC" Margin="20" Height="150" CornerRadius="5" Padding="20 0">
+ <Border.Effect>
+ <DropShadowEffect ShadowDepth="0" BlurRadius="10" Color="Gray" />
+ </Border.Effect>
+ <DockPanel>
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center" DockPanel.Dock="Left">
+ <Button Style="{StaticResource MaterialDesignFlatButton}" Width="80" Height="80" Padding="0" Command="{Binding BackCommand}" IsEnabled="{Binding IsFree}">
+ <materialDesign:PackIcon Kind="ArrowLeft" Width="60" Height="60" />
+ </Button>
+
+ <Button Style="{StaticResource MaterialDesignFlatButton}" Width="80" Height="80" Padding="0" Command="{Binding RefreshCommand}" IsEnabled="{Binding IsFree}">
+ <materialDesign:PackIcon Kind="Refresh" Width="60" Height="60" />
+ </Button>
+ </StackPanel>
+
+ <Border DockPanel.Dock="Right" Width="250" Margin="0 20" Background="{StaticResource AccentColorBrush}" TextElement.Foreground="White" CornerRadius="5" Padding="10">
+ <DockPanel>
+ <TextBlock DockPanel.Dock="Top" FontSize="18" FontWeight="Bold" FontStyle="Italic" HorizontalAlignment="Center">STORAGE</TextBlock>
+ <StackPanel>
+ <TextBlock Margin="0 5 0 0">
+ <Run>Root:</Run>
+ <Run FontWeight="Bold" FontStyle="Italic" Text="{Binding StorageManager.StorageDrive.Root}"></Run>
+ </TextBlock>
+ <TextBlock Margin="0 5 0 0">
+ <Run>Capacity:</Run>
+ <Run FontWeight="Bold" FontStyle="Italic" Text="{Binding StorageManager.StorageDrive.Capacity,Converter={StaticResource ByteArrayToFileSizeConverter}}"></Run>
+ </TextBlock>
+ <TextBlock Margin="0 5 0 0">
+ <Run>Free Space:</Run>
+ <Run FontWeight="Bold" FontStyle="Italic" Text="{Binding StorageManager.StorageDrive.FreeSpace,Converter={StaticResource ByteArrayToFileSizeConverter}}"></Run>
+ </TextBlock>
+ </StackPanel>
+ </DockPanel>
+ </Border>
+
+ <DockPanel VerticalAlignment="Center" Margin="50 0 50 0">
+ <Button Margin="10 0 0 0" DockPanel.Dock="Right" Style="{StaticResource MaterialDesignFlatButton}" Width="80" Height="80" Padding="0" Command="{Binding GoCommand}" IsEnabled="{Binding IsFree}">
+ <materialDesign:PackIcon Kind="SubdirectoryArrowRight" Width="60" Height="60" />
+ </Button>
+ <Border Height="35" Background="{StaticResource AccentColorBrush}" CornerRadius="5" Padding="5" IsEnabled="{Binding IsFree}">
+ <TextBox Style="{x:Null}" Background="Transparent" Foreground="White" FontSize="18" BorderThickness="0" CaretBrush="White" Text="{Binding CurrentPath,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
+ <TextBox.InputBindings>
+ <KeyBinding Command="{Binding Path=GoCommand}" Key="Enter"/>
+ </TextBox.InputBindings>
+ </TextBox>
+ </Border>
+ </DockPanel>
+ </DockPanel>
+ </Border>
+
+ <Grid Margin="20">
+ <Grid>
+ <Grid.RowDefinitions>
+ <RowDefinition Height="100*" MinHeight="150" />
+ <RowDefinition Height="5" />
+ <RowDefinition Height="40*" MinHeight="150" />
+ </Grid.RowDefinitions>
+ <Border Background="#8BFFFFFF" CornerRadius="5" Padding="20">
+ <DataGrid x:Name="gridStorageItems" IsEnabled="{Binding IsFree}" MouseDoubleClick="DataGrid_MouseDoubleClick" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserResizeRows="False" CanUserSortColumns="True" IsReadOnly="True" Background="Transparent" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ItemsSource="{Binding StorageManager.CurrentFolder.Items}" SelectedItem="{Binding SelectedStorageItem}">
+ <DataGrid.CellStyle>
+ <Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
+ <Setter Property="BorderThickness" Value="0"/>
+ <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
+ <Setter Property="VerticalContentAlignment" Value="Center"></Setter>
+ </Style>
+ </DataGrid.CellStyle>
+ <DataGrid.Columns>
+ <DataGridTemplateColumn Width="100">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <Image Width="32" Height="32" HorizontalAlignment="Left" Source="{Binding Converter={StaticResource StorageItemToImageConverter}}"></Image>
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ <DataGridTemplateColumn Header="NAME" Width="1*" SortMemberPath="Name">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <TextBlock Text="{Binding Name}" VerticalAlignment="Center" FontSize="14" />
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ <DataGridTemplateColumn Header="TYPE" Width="150" SortMemberPath="Attribute">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <TextBlock Text="{Binding Attribute}" VerticalAlignment="Center" FontSize="14" />
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ <DataGridTemplateColumn Header="SIZE" Width="150" SortMemberPath="Length">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <TextBlock Text="{Binding Length,Converter={StaticResource ByteArrayToFileSizeConverter},FallbackValue='',TargetNullValue=''}" VerticalAlignment="Center" FontSize="14" />
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ <DataGridTemplateColumn Header="LAST MODIFIED" Width="200" SortMemberPath="LastModified">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <TextBlock Text="{Binding LastModified}" VerticalAlignment="Center" FontSize="14" />
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ </DataGrid.Columns>
+ </DataGrid>
+ </Border>
+
+ <GridSplitter Grid.Row="1" Height="5" VerticalAlignment="Center" HorizontalAlignment="Stretch" Background="Gray" Margin="5 0" />
+
+ <Border Background="#8BFFFFFF" CornerRadius="5" Padding="20" Grid.Row="3">
+ <DockPanel>
+ <TextBlock DockPanel.Dock="Top" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="20" FontStyle="Italic" Foreground="{StaticResource AccentColorBrush}" FontWeight="Bold">FILE TRANSFERS</TextBlock>
+ <DataGrid AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserResizeRows="False" CanUserSortColumns="False" IsReadOnly="True" Background="Transparent" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ItemsSource="{Binding FileHandlers}">
+ <DataGrid.CellStyle>
+ <Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
+ <Setter Property="BorderThickness" Value="0"/>
+ <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
+ <Setter Property="VerticalContentAlignment" Value="Center"></Setter>
+ </Style>
+ </DataGrid.CellStyle>
+ <DataGrid.Columns>
+ <DataGridTemplateColumn Width="100">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <materialDesign:PackIcon Width="32" Height="32" HorizontalAlignment="Left">
+ <materialDesign:PackIcon.Style>
+ <Style TargetType="materialDesign:PackIcon">
+ <Setter Property="Kind" Value="Download"></Setter>
+ <Setter Property="Foreground" Value="#20BB20"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding Type}" Value="Upload">
+ <Setter Property="Kind" Value="Upload"></Setter>
+ <Setter Property="Foreground" Value="#E76311"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </materialDesign:PackIcon.Style>
+ </materialDesign:PackIcon>
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ <DataGridTemplateColumn Header="FILE" Width="450">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <TextBlock Text="{Binding FilePath}" TextTrimming="CharacterEllipsis" VerticalAlignment="Center" FontSize="14" />
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ <DataGridTemplateColumn Header="PROGRESS" Width="1*">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <ProgressBar Height="15" Margin="0 0 30 0" VerticalAlignment="Center" Maximum="{Binding Handler.Total,Mode=OneWay}" Value="{Binding Handler.Current,Mode=OneWay}">
+ <ProgressBar.Style>
+ <Style TargetType="ProgressBar">
+ <Setter Property="Foreground" Value="#2FD42F"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding Handler.Status}" Value="Canceled">
+ <Setter Property="Foreground" Value="#EF832B"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding Handler.Status}" Value="Failed">
+ <Setter Property="Foreground" Value="#E11A1A"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </ProgressBar.Style>
+ </ProgressBar>
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ <DataGridTemplateColumn Header="STATUS" Width="150">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <TextBlock Text="{Binding Handler.Status}" VerticalAlignment="Center" FontSize="14" FontWeight="SemiBold" FontStyle="Italic" />
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ <DataGridTemplateColumn Width="150">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <ContentControl Content="{Binding}">
+ <ContentControl.Style>
+ <Style TargetType="ContentControl">
+ <Setter Property="ContentTemplate">
+ <Setter.Value>
+ <DataTemplate></DataTemplate>
+ </Setter.Value>
+ </Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding Handler.Status}" Value="Active">
+ <Setter Property="ContentTemplate">
+ <Setter.Value>
+ <DataTemplate>
+ <Button Command="{Binding Source={x:Reference control},Path=DataContext.CancelFileHandlerCommand}" CommandParameter="{Binding}" Margin="5" Background="#FF6A6A" BorderBrush="#FF6A6A">CANCEL</Button>
+ </DataTemplate>
+ </Setter.Value>
+ </Setter>
+ </DataTrigger>
+ <MultiDataTrigger>
+ <MultiDataTrigger.Conditions>
+ <Condition Binding="{Binding Handler.Status}" Value="Completed"></Condition>
+ <Condition Binding="{Binding Type}" Value="Download"></Condition>
+ </MultiDataTrigger.Conditions>
+ <Setter Property="ContentTemplate">
+ <Setter.Value>
+ <DataTemplate>
+ <Button Command="{Binding Source={x:Reference control},Path=DataContext.OpenFileHandlerCommand}" CommandParameter="{Binding}" Margin="5" Background="#2CC62C" BorderBrush="#2CC62C">OPEN</Button>
+ </DataTemplate>
+ </Setter.Value>
+ </Setter>
+ </MultiDataTrigger>
+ </Style.Triggers>
+ </Style>
+ </ContentControl.Style>
+ </ContentControl>
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ <DataGridTemplateColumn Width="60">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <Button Foreground="#FF5A5A" Style="{StaticResource MaterialDesignFlatButton}" Padding="0" Width="24" Height="24" Command="{Binding Source={x:Reference control},Path=DataContext.RemoveFileHandlerCommand}" CommandParameter="{Binding}" Margin="5">
+ <materialDesign:PackIcon Kind="Close" Width="24" Height="24" />
+ </Button>
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ </DataGrid.Columns>
+ </DataGrid>
+ </DockPanel>
+ </Border>
+ </Grid>
+ </Grid>
+ </DockPanel>
+ </Grid>
+ </DockPanel>
+ </Grid>
+ </Grid>
+</UserControl>
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Views/MainView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Views/MainView.xaml.cs
new file mode 100644
index 000000000..5da808b8c
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Views/MainView.xaml.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using Tango.Integration.Storage;
+using Tango.MachineStudio.Storage.ViewModels;
+
+namespace Tango.MachineStudio.Storage.Views
+{
+ /// <summary>
+ /// Interaction logic for MainView.xaml
+ /// </summary>
+ public partial class MainView : UserControl
+ {
+ private MainViewVM _vm;
+
+ public MainView()
+ {
+ InitializeComponent();
+ Loaded += (_, __) =>
+ {
+ _vm = DataContext as MainViewVM;
+ _vm.CurrentFolderChanged += _vm_CurrentFolderChanged;
+ };
+
+ }
+
+ private void _vm_CurrentFolderChanged(object sender, EventArgs e)
+ {
+ ScrollViewer scrollViewer = gridStorageItems.FindChild<ScrollViewer>();
+ scrollViewer.ScrollToVerticalOffset(0);
+ }
+
+ private void DataGrid_MouseDoubleClick(object sender, MouseButtonEventArgs e)
+ {
+ _vm.OnStorageItemDoubleClicked(gridStorageItems.SelectedItem as StorageItem);
+ }
+ }
+}
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/app.config b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/app.config
new file mode 100644
index 000000000..5d794b958
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/app.config
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <dependentAssembly>
+ <assemblyIdentity name="System.Reactive.Core" publicKeyToken="94bc3704cddfc263" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-3.0.3000.0" newVersion="3.0.3000.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-1.2.2.0" newVersion="1.2.2.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Reflection.Metadata" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-1.4.2.0" newVersion="1.4.2.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.IO.FileSystem" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.IO.FileSystem.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Security.Cryptography.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Xml.XPath.XDocument" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Console" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Diagnostics.StackTrace" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
+ </dependentAssembly>
+ </assemblyBinding>
+ </runtime>
+</configuration> \ No newline at end of file
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/packages.config b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/packages.config
new file mode 100644
index 000000000..0580e26aa
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/packages.config
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="MahApps.Metro" version="1.5.0" targetFramework="net461" />
+ <package id="MaterialDesignColors" version="1.1.2" targetFramework="net461" />
+ <package id="MaterialDesignThemes" version="2.3.1.953" targetFramework="net461" />
+</packages> \ No newline at end of file