using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using Tango.Core.Commands;
using Tango.Core.DI;
using Tango.Core.Threading;
using Tango.FSE.Common;
using Tango.FSE.Common.Notifications;
using Tango.FSE.Common.RemoteActions;
using Tango.FSE.Common.RemoteDesktop;
using Tango.RemoteDesktop.Frames;
using Tango.RemoteDesktop.Network;
namespace Tango.FSE.PPCConsole.ViewModels
{
///
/// Represents the PPC remote dekstop view model.
///
///
public class RemoteDesktopViewVM : FSEViewModel
{
private DateTime _recordingStartTime;
private Timer _recordingTimer;
private VideoRecordingHandler _recordingHandler;
private SnackbarItem _recordingSnackbarItem;
private System.Windows.Point _lastMouseLocation;
#region Properties
private BitmapSource _source;
///
/// Gets or sets the remote desktop image source.
///
public BitmapSource Source
{
get { return _source; }
set { _source = value; RaisePropertyChangedAuto(); }
}
private bool _isRecording;
public bool IsRecording
{
get { return _isRecording; }
set { _isRecording = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); }
}
private TimeSpan _recordingTime;
public TimeSpan RecordingTime
{
get { return _recordingTime; }
set { _recordingTime = value; RaisePropertyChangedAuto(); }
}
private bool _cursorVisible;
public bool CursorVisible
{
get { return _cursorVisible; }
set { _cursorVisible = value; RaisePropertyChangedAuto(); SetCursorVisibility(); }
}
private bool _touchMode;
public bool TouchMode
{
get { return _touchMode; }
set { _touchMode = value; RaisePropertyChangedAuto(); }
}
[TangoInject]
public IRemoteActionsProvider RemoteActionsProvider { get; set; }
#endregion
#region Commands
///
/// Starts a remote desktop session with the currently connected machine.
///
public RelayCommand StartCommand { get; set; }
///
/// Stops the current remote desktop session.
///
public RelayCommand StopCommand { get; set; }
///
/// Executes the task manager on the remote PPC.
///
public RelayCommand OpenTaskManagerCommand { get; set; }
///
/// Hides the remote PPC application and opens the windows shell.
///
public RelayCommand HideAndOpenShellCommand { get; set; }
///
/// Save current desktop frame to image
///
public RelayCommand TakeSnapshotCommand { get; set; }
///
/// Starts the video recording.
///
public RelayCommand StartRecordingCommand { get; set; }
///
/// Stops the video recording.
///
public RelayCommand StopRecordingCommand { get; set; }
///
/// Gets or sets the restart application command.
///
public RelayCommand RestartApplicationCommand { get; set; }
#endregion
#region Constructors
///
/// Initializes a new instance of the class.
///
public RemoteDesktopViewVM()
{
_recordingTimer = new Timer(1000);
_recordingTimer.Elapsed += _recordingTimer_Elapsed;
_recordingTimer.Stop();
StartCommand = new RelayCommand(StartRemoteDesktop);
StopCommand = new RelayCommand(StopRemoteDesktop);
OpenTaskManagerCommand = new RelayCommand(OpenTaskManager);
HideAndOpenShellCommand = new RelayCommand(HideAndOpenShell);
TakeSnapshotCommand = new RelayCommand(TakeSnapshot);
StartRecordingCommand = new RelayCommand(StartRecording);
StopRecordingCommand = new RelayCommand(StopRecording, () => IsRecording);
RestartApplicationCommand = new RelayCommand(RestartApplication);
}
#endregion
#region Override Methods
public override void OnApplicationStarted()
{
base.OnApplicationStarted();
RemoteDesktopProvider.FrameReceived += RemoteDesktopProvider_FrameReceived;
RemoteDesktopProvider.SessionStopped += RemoteDesktopProvider_SessionStopped;
MachineProvider.MachineConnected += MachineProvider_MachineConnected;
}
public override async Task OnApplicationLogout()
{
if (RemoteDesktopProvider.InSession)
{
if (await NotificationProvider.ShowWarningQuestion("The remote desktop session with the remote machine will be closed.\nAre you sure you want to log out?"))
{
await RemoteDesktopProvider.EndSession();
return true;
}
else
{
return false;
}
}
else
{
return true;
}
}
#endregion
#region Event Handlers
private void MachineProvider_MachineConnected(object sender, Common.Connection.MachineConnectedEventArgs e)
{
Source = null;
}
private void RemoteDesktopProvider_FrameReceived(object sender, DesktopFrameReceivedEventArgs e)
{
Source = e.Source;
_cursorVisible = e.CursorVisible;
RaisePropertyChanged(nameof(CursorVisible));
}
private void RemoteDesktopProvider_SessionStopped(object sender, EventArgs e)
{
_cursorVisible = false;
RaisePropertyChanged(nameof(CursorVisible));
}
#endregion
#region Start / Stop Session
private async void StartRemoteDesktop()
{
try
{
await RemoteDesktopProvider.StartSession();
}
catch (Exception ex)
{
await NotificationProvider.ShowError($"Error starting the remote desktop session.\n{ex.FlattenMessage()}");
}
}
private async void StopRemoteDesktop()
{
try
{
await RemoteDesktopProvider.EndSession();
}
catch (Exception ex)
{
await NotificationProvider.ShowError($"Error stopping the remote desktop session.\n{ex.FlattenMessage()}");
}
}
#endregion
#region Mouse & Keyboard Handlers From View
public void OnMouseDown(MouseButton changedButton, System.Windows.Point point, System.Windows.Size size)
{
_lastMouseLocation = new System.Windows.Point(point.X, point.Y);
if (!TouchMode)
{
RemoteDesktopProvider.MouseDown(changedButton, point, size);
}
else
{
RemoteDesktopProvider.TouchDown(point, size);
}
}
public void OnMouseUp(MouseButton changedButton, System.Windows.Point point, System.Windows.Size size)
{
if (!TouchMode)
{
RemoteDesktopProvider.MouseUp(changedButton, point, size);
}
else
{
RemoteDesktopProvider.TouchUp();
}
}
public void OnMouseMove(System.Windows.Point point, System.Windows.Size size)
{
if (!TouchMode)
{
RemoteDesktopProvider.MouseMove(point, size);
}
else
{
var delta = new System.Windows.Point(point.X - _lastMouseLocation.X, point.Y - _lastMouseLocation.Y);
RemoteDesktopProvider.TouchMove((int)delta.X, (int)delta.Y, size);
}
_lastMouseLocation = new System.Windows.Point(point.X, point.Y);
}
public void OnMouseDoubleClick(MouseButton changedButton, System.Windows.Point point, System.Windows.Size size)
{
RemoteDesktopProvider.MouseDoubleClick(changedButton, point, size);
}
public void OnMouseScroll(int delta, System.Windows.Point point, System.Windows.Size size)
{
RemoteDesktopProvider.MouseScroll(delta, point, size);
}
public void OnKeyboardDown(Key key, bool ctrlDown, bool shitDown, bool altDown)
{
RemoteDesktopProvider.KeyboardDown(key, ctrlDown, shitDown, altDown);
}
public void OnKeyboardUp(Key key, bool ctrlDown, bool shitDown, bool altDown)
{
RemoteDesktopProvider.KeyboardUp(key, ctrlDown, shitDown, altDown);
}
private void SetCursorVisibility()
{
RemoteDesktopProvider.SetRemoteCursorVisibility(CursorVisible);
}
#endregion
#region Snapshot
private async void TakeSnapshot()
{
var snapshot = Source.Clone();
await Task.Delay(500); //Delay for blink animation..
var result = await StorageProvider.SaveFile("Save Snapshot", "Jpeg Files|*.jpg", $"TangoApp_{DateTime.Now.ToFileName()}.jpg", ".jpg");
if (result.Confirmed)
{
snapshot.SaveJpegFile(result.SelectedItem, 100);
NotificationProvider.PushSnackbarItem(MessageType.Success, "Remote Desktop Snapshot Saved", true, "Remote desktop snapshot saved successfully.\nTap to view the image file.", TimeSpan.FromSeconds(8), null, () =>
{
StorageProvider.ShowInExplorer(result.SelectedItem);
});
}
}
#endregion
#region Remote Actions
private void OpenTaskManager()
{
RemoteDesktopProvider.KeyboardDown(Key.Escape, true, true, false);
RemoteDesktopProvider.KeyboardDown(Key.Escape, false, false, false);
}
private void HideAndOpenShell()
{
RemoteDesktopProvider.SendCommand(RemoteDesktopCommand.HideAndOpenShell);
}
private async void RestartApplication()
{
if (await NotificationProvider.ShowWarningQuestion("Are you sure you want to restart the remote application?", "RESTART"))
{
bool restarted = false;
try
{
try
{
await RemoteDesktopProvider.EndSession();
}
catch { }
await Task.Factory.StartNew(RemoteActionsProvider.RestartApplication);
restarted = true;
}
catch (Exception ex)
{
LogManager.Log(ex, "Error restarting the remote application.");
}
if (restarted)
{
try
{
await MachineProvider.DisconnectAndWaitForReconnection(TimeSpan.FromSeconds(20), TimeSpan.FromMinutes(1), "The remote PPC is now restarting...");
if (MachineProvider.IsConnected)
{
StartRemoteDesktop();
}
}
catch { }
}
}
}
#endregion
#region Video Recording
private void _recordingTimer_Elapsed(object sender, ElapsedEventArgs e)
{
RecordingTime = DateTime.Now - _recordingStartTime;
}
private void StartRecording()
{
if (!IsRecording)
{
RecordingTime = TimeSpan.Zero;
_recordingStartTime = DateTime.Now;
_recordingTimer.Start();
_recordingHandler = RemoteDesktopProvider.CreateRecordingHandler();
_recordingHandler.Progress += _recordingHandler_Progress;
IsRecording = true;
}
}
private async void StopRecording()
{
if (IsRecording)
{
IsRecording = false;
var result = await StorageProvider.SaveFile("Save Video Recording", "Mp4 Video Files|*.mp4", $"TangoApp_{DateTime.Now.ToFileName()}", ".mp4");
if (result.Confirmed)
{
_recordingHandler.Stop();
try
{
_recordingSnackbarItem = NotificationProvider.PushProgressSnackbar("Encoding Video File", "Encoding remote desktop recording to disk...");
await _recordingHandler.Save(result.SelectedItem);
_recordingSnackbarItem.ProgressCompleted("Video encoding completed.\nTap to view the video file.", null, () =>
{
StorageProvider.ShowInExplorer(result.SelectedItem);
});
}
catch (Exception ex)
{
LogManager.Log(ex, "Error saving remote desktop video recording.");
_recordingSnackbarItem.ProgressFailed($"Video encoding failed.\n{ex.FlattenMessage()}", TimeSpan.FromSeconds(5));
await NotificationProvider.ShowError($"Error saving video recording.\n{ex.FlattenMessage()}");
}
}
else
{
_recordingHandler.Cancel();
}
}
}
private void _recordingHandler_Progress(object sender, Core.TangoProgressChangedEventArgs e)
{
_recordingSnackbarItem.Message = $"Encoding remote desktop recording to disk ({(e.Progress.Value / e.Progress.Maximum * 100d).ToString("0")}%)...";
}
#endregion
}
}