diff --git a/ClientApp/App.xaml b/ClientApp/App.xaml
index 1400927..61cadcc 100644
--- a/ClientApp/App.xaml
+++ b/ClientApp/App.xaml
@@ -6,13 +6,25 @@
xmlns:views="clr-namespace:ClientApp.Views"
StartupUri="Views/MainWindow.xaml">
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ClientApp/ClientApp.csproj b/ClientApp/ClientApp.csproj
index 7b0bcaf..637f86c 100644
--- a/ClientApp/ClientApp.csproj
+++ b/ClientApp/ClientApp.csproj
@@ -7,6 +7,36 @@
Images\Logo\icon1.ico
+
+
+
+
+
+
+
+
+
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+
@@ -19,6 +49,10 @@
+
+
+
+
\ No newline at end of file
diff --git a/ClientApp/Images/gradient-geometric-shape-background_78532-374.jpg b/ClientApp/Images/CoolBackground.jpg
similarity index 100%
rename from ClientApp/Images/gradient-geometric-shape-background_78532-374.jpg
rename to ClientApp/Images/CoolBackground.jpg
diff --git a/ClientApp/Images/Icons/CheckMark.png b/ClientApp/Images/Icons/CheckMark.png
new file mode 100644
index 0000000..6bb2ed3
Binary files /dev/null and b/ClientApp/Images/Icons/CheckMark.png differ
diff --git a/ClientApp/Images/Icons/CrossMark.png b/ClientApp/Images/Icons/CrossMark.png
new file mode 100644
index 0000000..4a30bac
Binary files /dev/null and b/ClientApp/Images/Icons/CrossMark.png differ
diff --git a/ClientApp/Images/Logo/icon1.ico b/ClientApp/Images/Logo/icon1.ico
index 95760d6..faa56b4 100644
Binary files a/ClientApp/Images/Logo/icon1.ico and b/ClientApp/Images/Logo/icon1.ico differ
diff --git a/ClientApp/Images/Logo/icon1_small.ico b/ClientApp/Images/Logo/icon1_small.ico
new file mode 100644
index 0000000..95760d6
Binary files /dev/null and b/ClientApp/Images/Logo/icon1_small.ico differ
diff --git a/ClientApp/MagicCode/WindowResizer.cs b/ClientApp/MagicCode/WindowResizer.cs
new file mode 100644
index 0000000..c997d89
--- /dev/null
+++ b/ClientApp/MagicCode/WindowResizer.cs
@@ -0,0 +1,212 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Windows;
+using System.Windows.Interop;
+
+namespace ClientApp.MagicCode
+{
+ ///
+ /// Fixes the issue with Windows of Style covering the taskbar
+ ///
+ public class WindowResizer
+ {
+ #region Private Members
+
+ ///
+ /// The window to handle the resizing for
+ ///
+ private Window mWindow;
+
+ #endregion
+
+ #region Dll Imports
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ static extern bool GetCursorPos(out POINT lpPoint);
+
+ [DllImport("user32.dll")]
+ static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi);
+
+ [DllImport("user32.dll", SetLastError = true)]
+ static extern IntPtr MonitorFromPoint(POINT pt, MonitorOptions dwFlags);
+
+ #endregion
+
+ #region Constructor
+
+ ///
+ /// Default constructor
+ ///
+ /// The window to monitor and correctly maximize
+ /// The callback for the host to adjust the maximum available size if needed
+ public WindowResizer(Window window)
+ {
+ mWindow = window;
+
+ // Listen out for source initialized to setup
+ mWindow.SourceInitialized += Window_SourceInitialized;
+ }
+
+ #endregion
+
+ #region Initialize
+
+ ///
+ /// Initialize and hook into the windows message pump
+ ///
+ ///
+ ///
+ private void Window_SourceInitialized(object sender, System.EventArgs e)
+ {
+ // Get the handle of this window
+ var handle = (new WindowInteropHelper(mWindow)).Handle;
+ var handleSource = HwndSource.FromHwnd(handle);
+
+ // If not found, end
+ if (handleSource == null)
+ return;
+
+ // Hook into it's Windows messages
+ handleSource.AddHook(WindowProc);
+ }
+
+ #endregion
+
+ #region Windows Proc
+
+ ///
+ /// Listens out for all windows messages for this window
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private IntPtr WindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
+ {
+ switch (msg)
+ {
+ // Handle the GetMinMaxInfo of the Window
+ case 0x0024:/* WM_GETMINMAXINFO */
+ WmGetMinMaxInfo(hwnd, lParam);
+ handled = true;
+ break;
+ }
+
+ return (IntPtr)0;
+ }
+
+ #endregion
+
+ ///
+ /// Get the min/max window size for this window
+ /// Correctly accounting for the taskbar size and position
+ ///
+ ///
+ ///
+ private void WmGetMinMaxInfo(System.IntPtr hwnd, System.IntPtr lParam)
+ {
+ POINT lMousePosition;
+ GetCursorPos(out lMousePosition);
+
+ IntPtr lPrimaryScreen = MonitorFromPoint(new POINT(0, 0), MonitorOptions.MONITOR_DEFAULTTOPRIMARY);
+ MONITORINFO lPrimaryScreenInfo = new MONITORINFO();
+ if (GetMonitorInfo(lPrimaryScreen, lPrimaryScreenInfo) == false)
+ {
+ return;
+ }
+
+ IntPtr lCurrentScreen = MonitorFromPoint(lMousePosition, MonitorOptions.MONITOR_DEFAULTTONEAREST);
+
+ MINMAXINFO lMmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO));
+
+ if (lPrimaryScreen.Equals(lCurrentScreen) == true)
+ {
+ lMmi.ptMaxPosition.X = lPrimaryScreenInfo.rcWork.Left;
+ lMmi.ptMaxPosition.Y = lPrimaryScreenInfo.rcWork.Top;
+ lMmi.ptMaxSize.X = lPrimaryScreenInfo.rcWork.Right - lPrimaryScreenInfo.rcWork.Left;
+ lMmi.ptMaxSize.Y = lPrimaryScreenInfo.rcWork.Bottom - lPrimaryScreenInfo.rcWork.Top;
+ }
+ else
+ {
+ lMmi.ptMaxPosition.X = lPrimaryScreenInfo.rcMonitor.Left;
+ lMmi.ptMaxPosition.Y = lPrimaryScreenInfo.rcMonitor.Top;
+ lMmi.ptMaxSize.X = lPrimaryScreenInfo.rcMonitor.Right - lPrimaryScreenInfo.rcMonitor.Left;
+ lMmi.ptMaxSize.Y = lPrimaryScreenInfo.rcMonitor.Bottom - lPrimaryScreenInfo.rcMonitor.Top;
+ }
+
+ // Now we have the max size, allow the host to tweak as needed
+ Marshal.StructureToPtr(lMmi, lParam, true);
+ }
+ }
+
+ #region Dll Helper Structures
+
+ enum MonitorOptions : uint
+ {
+ MONITOR_DEFAULTTONULL = 0x00000000,
+ MONITOR_DEFAULTTOPRIMARY = 0x00000001,
+ MONITOR_DEFAULTTONEAREST = 0x00000002
+ }
+
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ public class MONITORINFO
+ {
+ public int cbSize = Marshal.SizeOf(typeof(MONITORINFO));
+ public Rectangle rcMonitor = new Rectangle();
+ public Rectangle rcWork = new Rectangle();
+ public int dwFlags = 0;
+ }
+
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Rectangle
+ {
+ public int Left, Top, Right, Bottom;
+
+ public Rectangle(int left, int top, int right, int bottom)
+ {
+ this.Left = left;
+ this.Top = top;
+ this.Right = right;
+ this.Bottom = bottom;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct MINMAXINFO
+ {
+ public POINT ptReserved;
+ public POINT ptMaxSize;
+ public POINT ptMaxPosition;
+ public POINT ptMinTrackSize;
+ public POINT ptMaxTrackSize;
+ };
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct POINT
+ {
+ ///
+ /// x coordinate of point.
+ ///
+ public int X;
+ ///
+ /// y coordinate of point.
+ ///
+ public int Y;
+
+ ///
+ /// Construct a point of coordinates (x,y).
+ ///
+ public POINT(int x, int y)
+ {
+ this.X = x;
+ this.Y = y;
+ }
+ }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/ClientApp/Utils/Client.cs b/ClientApp/Utils/Client.cs
index 58b0177..963c1d3 100644
--- a/ClientApp/Utils/Client.cs
+++ b/ClientApp/Utils/Client.cs
@@ -10,7 +10,7 @@ using Util;
namespace ClientApp.Utils
{
public delegate void EngineCallback();
- public class Client : IDataReceiver
+ public class Client : IDataReceiver, IDisposable
{
public EngineCallback engineConnectFailed;
public EngineCallback engineConnectSuccess;
@@ -46,6 +46,7 @@ namespace ClientApp.Utils
engineConnection = EngineConnection.INSTANCE;
engineConnection.OnNoTunnelId = RetryEngineConnection;
engineConnection.OnSuccessFullConnection = engineConnected;
+ engineConnection.OnEngineDisconnect = RetryEngineConnection;
if (!engineConnection.Connected) engineConnection.Connect();
}
@@ -87,6 +88,10 @@ namespace ClientApp.Utils
/// the result of the async read
private void OnRead(IAsyncResult ar)
{
+ if (ar == null || (!ar.IsCompleted) || (!this.stream.CanRead))
+ return;
+
+
int receivedBytes = this.stream.EndRead(ar);
if (totalBufferReceived + receivedBytes > 1024)
@@ -122,7 +127,7 @@ namespace ClientApp.Utils
this.LoginViewModel.setLoginStatus(true);
this.connected = true;
initEngine();
-
+
}
else
{
@@ -224,7 +229,7 @@ namespace ClientApp.Utils
/// the message
public void Bike(byte[] bytes)
{
-
+
if (!sessionRunning)
{
return;
@@ -266,7 +271,7 @@ namespace ClientApp.Utils
///
public void tryLogin(string username, string password)
{
-
+
string hashPassword = Util.Hasher.HashString(password);
byte[] message = DataParser.getJsonMessage(DataParser.GetLoginJson(username, hashPassword));
@@ -288,5 +293,13 @@ namespace ClientApp.Utils
{
this.LoginViewModel = loginViewModel;
}
+
+ public void Dispose()
+ {
+ Debug.WriteLine("client dispose called");
+ this.stream.Dispose();
+ this.client.Dispose();
+ this.handler.stop();
+ }
}
}
diff --git a/ClientApp/Utils/EngineConnection.cs b/ClientApp/Utils/EngineConnection.cs
index ea699a3..3706e87 100644
--- a/ClientApp/Utils/EngineConnection.cs
+++ b/ClientApp/Utils/EngineConnection.cs
@@ -10,16 +10,17 @@ using LibNoise.Primitive;
namespace ClientApp.Utils
{
public delegate void HandleSerial(string message);
- public delegate void HandleNoTunnelId();
- public delegate void OnSuccessfullConnection();
+ public delegate void EngineDelegate();
public sealed class EngineConnection
{
private static EngineConnection instance = null;
private static readonly object padlock = new object();
private static System.Timers.Timer updateTimer;
- public HandleNoTunnelId OnNoTunnelId;
- public OnSuccessfullConnection OnSuccessFullConnection;
+ private static System.Timers.Timer noVRResponseTimer;
+ public EngineDelegate OnNoTunnelId;
+ public EngineDelegate OnSuccessFullConnection;
+ public EngineDelegate OnEngineDisconnect;
private static PC[] PCs = {
@@ -42,6 +43,7 @@ namespace ClientApp.Utils
private static string headId = string.Empty;
private static string groundPlaneId = string.Empty;
private static string terrainId = string.Empty;
+ private static string lastMessage = "No message received yet";
public float BikeSpeed { get; set; }
public float BikePower { get; set; }
@@ -67,6 +69,12 @@ namespace ClientApp.Utils
updateTimer.Elapsed += UpdateTimer_Elapsed;
updateTimer.AutoReset = true;
updateTimer.Enabled = false;
+
+ noVRResponseTimer = new System.Timers.Timer(15000);
+ noVRResponseTimer.Elapsed += noVRResponseTimeout;
+ noVRResponseTimer.AutoReset = false;
+ noVRResponseTimer.Enabled = false;
+
}
private void UpdateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
@@ -74,6 +82,21 @@ namespace ClientApp.Utils
UpdateInfoPanel();
}
+ private void noVRResponseTimeout(object sender, System.Timers.ElapsedEventArgs e)
+ {
+ Write("VR RESPONSE TIMEOUT");
+ noVRResponseTimer.Stop();
+ sessionId = string.Empty;
+ tunnelId = string.Empty;
+ cameraId = string.Empty;
+ routeId = string.Empty;
+ panelId = string.Empty;
+ bikeId = string.Empty;
+ groundPlaneId = string.Empty;
+ terrainId = string.Empty;
+ OnEngineDisconnect?.Invoke();
+ }
+
///
/// Singleton constructor
///
@@ -165,6 +188,7 @@ namespace ClientApp.Utils
{
Write("got tunnel id! " + tunnelId);
Connected = true;
+ noVRResponseTimer.Enabled = true;
OnSuccessFullConnection?.Invoke();
}
}
@@ -176,6 +200,9 @@ namespace ClientApp.Utils
//Console.WriteLine("Got serial " + serial);
if (serialResponses.ContainsKey(serial)) serialResponses[serial].Invoke(message);
}
+
+ noVRResponseTimer.Stop();
+ noVRResponseTimer.Start();
}
public void initScene()
@@ -297,6 +324,11 @@ namespace ClientApp.Utils
{
// TODO check if is drawn
});
+ SendMessageAndOnResponse(mainCommand.showMessage(panelId, "message", lastMessage), "message",
+ (message) =>
+ {
+ // TODO check if is drawn
+ });
// Check if every text is drawn!
diff --git a/ClientApp/ValueConverters/BoolToMarkConverter.cs b/ClientApp/ValueConverters/BoolToMarkConverter.cs
new file mode 100644
index 0000000..ea03634
--- /dev/null
+++ b/ClientApp/ValueConverters/BoolToMarkConverter.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Windows.Data;
+using System.Windows.Media.Imaging;
+
+namespace ClientApp.ValueConverters
+{
+ //[ValueConversion(typeof(bool), typeof(BitmapImage))]
+
+ class BoolToMarkConverter : IValueConverter
+ {
+ public BitmapImage TrueImage { get; set; } = new BitmapImage(new Uri("pack://application:,,,/Images/Icons/CheckMark.png"));
+ public BitmapImage FalseImage { get; set; } = new BitmapImage(new Uri("pack://application:,,,/Images/Icons/CrossMark.png"));
+
+ public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ if (!(value is bool))
+ {
+ return null;
+ }
+
+ bool b = (bool)value;
+ if (b)
+ {
+ return this.TrueImage;
+ }
+ else
+ {
+ return this.FalseImage;
+ }
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/ClientApp/ViewModels/LoginViewModel.cs b/ClientApp/ViewModels/LoginViewModel.cs
index 1179ec2..7b9bfcf 100644
--- a/ClientApp/ViewModels/LoginViewModel.cs
+++ b/ClientApp/ViewModels/LoginViewModel.cs
@@ -20,14 +20,14 @@ namespace ClientApp.ViewModels
public bool InvertedLoginStatus { get; set; }
- private MainWindowViewModel mainWindowViewModel;
+ private MainWindowViewModel MainWindowViewModel;
public LoginViewModel(MainWindowViewModel mainWindowViewModel)
{
- this.mainWindowViewModel = mainWindowViewModel;
+ this.MainWindowViewModel = mainWindowViewModel;
LoginCommand = new RelayCommand