2019-03-21 16:05:16 +01:00
/ *
2022-01-21 16:33:52 +01:00
* Copyright ( c ) 2022 ETH Zürich , Educational Development and Technology ( LET )
2019-03-21 16:05:16 +01:00
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2.0 . If a copy of the MPL was not distributed with this
* file , You can obtain one at http : //mozilla.org/MPL/2.0/.
* /
using System ;
using System.Threading.Tasks ;
using System.Windows ;
using System.Windows.Controls ;
2019-12-06 14:23:07 +01:00
using System.Windows.Controls.Primitives ;
2019-03-21 16:05:16 +01:00
using System.Windows.Media ;
using FontAwesome.WPF ;
2021-03-18 23:12:07 +01:00
using SafeExamBrowser.Core.Contracts.Resources.Icons ;
2019-09-04 11:46:30 +02:00
using SafeExamBrowser.I18n.Contracts ;
2022-04-19 18:21:29 +02:00
using SafeExamBrowser.SystemComponents.Contracts.Network ;
2019-08-30 09:55:26 +02:00
using SafeExamBrowser.UserInterface.Contracts.Shell ;
2019-05-08 09:56:34 +02:00
using SafeExamBrowser.UserInterface.Shared.Utilities ;
2019-03-21 16:05:16 +01:00
2020-03-17 10:37:08 +01:00
namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar
2019-03-21 16:05:16 +01:00
{
2022-04-19 18:21:29 +02:00
internal partial class NetworkControl : UserControl , ISystemControl
2019-03-21 16:05:16 +01:00
{
2022-04-19 18:21:29 +02:00
private readonly INetworkAdapter adapter ;
private readonly IText text ;
2019-09-04 11:46:30 +02:00
2022-04-19 18:21:29 +02:00
internal NetworkControl ( INetworkAdapter adapter , IText text )
2019-03-21 16:05:16 +01:00
{
2022-04-19 18:21:29 +02:00
this . adapter = adapter ;
2019-09-04 11:46:30 +02:00
this . text = text ;
InitializeComponent ( ) ;
InitializeWirelessNetworkControl ( ) ;
2019-03-21 16:05:16 +01:00
}
2019-09-04 11:46:30 +02:00
public void Close ( )
2019-03-21 16:05:16 +01:00
{
2019-09-04 11:46:30 +02:00
Dispatcher . InvokeAsync ( ( ) = > Popup . IsOpen = false ) ;
2019-03-21 16:05:16 +01:00
}
2019-09-04 11:46:30 +02:00
private void InitializeWirelessNetworkControl ( )
2019-03-21 16:05:16 +01:00
{
2019-09-04 11:46:30 +02:00
var originalBrush = Button . Background ;
2022-04-19 18:21:29 +02:00
adapter . Changed + = ( ) = > Dispatcher . InvokeAsync ( Update ) ;
2019-09-04 11:46:30 +02:00
Button . Click + = ( o , args ) = > Popup . IsOpen = ! Popup . IsOpen ;
2023-02-13 13:39:53 +01:00
var lastOpenedBySpacePress = DateTime . MinValue ;
Button . PreviewKeyDown + = ( o , args ) = >
{
if ( args . Key = = System . Windows . Input . Key . Space ) // for some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation, we record the space bar event and leave the popup open for at least 3 seconds
{
lastOpenedBySpacePress = DateTime . Now ;
}
} ;
Button . MouseLeave + = ( o , args ) = > Task . Delay ( 250 ) . ContinueWith ( _ = > Dispatcher . Invoke ( ( ) = >
{
if ( Popup . IsOpen & & ( DateTime . Now - lastOpenedBySpacePress ) . TotalSeconds < 3 )
{
return ;
}
Popup . IsOpen = Popup . IsMouseOver ;
} ) ) ;
2019-12-06 14:23:07 +01:00
Popup . CustomPopupPlacementCallback = new CustomPopupPlacementCallback ( Popup_PlacementCallback ) ;
2019-09-04 11:46:30 +02:00
Popup . MouseLeave + = ( o , args ) = > Task . Delay ( 250 ) . ContinueWith ( _ = > Dispatcher . Invoke ( ( ) = > Popup . IsOpen = IsMouseOver ) ) ;
2022-04-19 18:21:29 +02:00
WirelessIcon . Child = GetWirelessIcon ( 0 ) ;
2019-09-04 11:46:30 +02:00
Popup . Opened + = ( o , args ) = >
2019-03-21 16:05:16 +01:00
{
2019-09-04 11:46:30 +02:00
Background = Brushes . LightGray ;
Button . Background = Brushes . LightGray ;
} ;
2019-03-21 16:05:16 +01:00
2019-09-04 11:46:30 +02:00
Popup . Closed + = ( o , args ) = >
{
Background = originalBrush ;
Button . Background = originalBrush ;
} ;
2019-03-21 16:05:16 +01:00
2022-04-19 18:21:29 +02:00
Update ( ) ;
2019-03-21 16:05:16 +01:00
}
2019-12-06 14:23:07 +01:00
private CustomPopupPlacement [ ] Popup_PlacementCallback ( Size popupSize , Size targetSize , Point offset )
{
return new [ ]
{
new CustomPopupPlacement ( new Point ( targetSize . Width / 2 - popupSize . Width / 2 , - popupSize . Height ) , PopupPrimaryAxis . None )
} ;
}
2022-04-19 18:21:29 +02:00
private void Update ( )
2019-03-21 16:05:16 +01:00
{
2022-04-19 18:21:29 +02:00
WirelessNetworksStackPanel . Children . Clear ( ) ;
2019-09-04 11:46:30 +02:00
2022-04-19 18:21:29 +02:00
foreach ( var network in adapter . GetWirelessNetworks ( ) )
2019-03-21 16:05:16 +01:00
{
2022-04-19 18:21:29 +02:00
var button = new NetworkButton ( network ) ;
2019-03-21 16:05:16 +01:00
2022-04-19 18:21:29 +02:00
button . NetworkSelected + = ( o , args ) = > adapter . ConnectToWirelessNetwork ( network . Id ) ;
2019-03-21 16:05:16 +01:00
2022-04-19 18:21:29 +02:00
if ( network . Status = = ConnectionStatus . Connected )
2019-09-04 11:46:30 +02:00
{
2022-04-19 18:21:29 +02:00
WirelessIcon . Child = GetWirelessIcon ( network . SignalStrength ) ;
2023-02-03 15:42:22 +01:00
UpdateText ( text . Get ( TextKey . SystemControl_NetworkWirelessConnected ) . Replace ( "%%NAME%%" , network . Name ) ) ;
2019-09-04 11:46:30 +02:00
}
2019-03-21 16:05:16 +01:00
2022-04-19 18:21:29 +02:00
WirelessNetworksStackPanel . Children . Add ( button ) ;
2019-09-04 11:46:30 +02:00
}
2019-03-21 16:05:16 +01:00
2022-04-19 18:21:29 +02:00
switch ( adapter . Type )
2019-03-21 16:05:16 +01:00
{
2022-04-19 18:21:29 +02:00
case ConnectionType . Wired :
Button . IsEnabled = false ;
2023-02-03 15:42:22 +01:00
UpdateText ( text . Get ( TextKey . SystemControl_NetworkWiredConnected ) ) ;
2022-04-19 18:21:29 +02:00
WiredIcon . Visibility = Visibility . Visible ;
WirelessIcon . Visibility = Visibility . Collapsed ;
2019-09-04 11:46:30 +02:00
break ;
2022-04-19 18:21:29 +02:00
case ConnectionType . Wireless :
Button . IsEnabled = true ;
WiredIcon . Visibility = Visibility . Collapsed ;
WirelessIcon . Visibility = Visibility . Visible ;
2019-09-04 11:46:30 +02:00
break ;
default :
2022-04-19 18:21:29 +02:00
Button . IsEnabled = false ;
2023-02-03 15:42:22 +01:00
UpdateText ( text . Get ( TextKey . SystemControl_NetworkNotAvailable ) ) ;
2022-04-19 18:21:29 +02:00
WiredIcon . Visibility = Visibility . Visible ;
WirelessIcon . Visibility = Visibility . Collapsed ;
2019-09-04 11:46:30 +02:00
break ;
}
2019-03-21 16:05:16 +01:00
2022-04-19 18:21:29 +02:00
switch ( adapter . Status )
{
case ConnectionStatus . Connected :
2023-02-03 15:42:22 +01:00
UpdateText ( text . Get ( TextKey . SystemControl_NetworkWiredConnected ) ) ;
2022-04-19 18:21:29 +02:00
NetworkStatusIcon . Rotation = 0 ;
NetworkStatusIcon . Source = ImageAwesome . CreateImageSource ( FontAwesomeIcon . Globe , Brushes . Green ) ;
NetworkStatusIcon . Spin = false ;
break ;
case ConnectionStatus . Connecting :
2023-02-03 15:42:22 +01:00
UpdateText ( text . Get ( TextKey . SystemControl_NetworkWirelessConnecting ) ) ;
2022-04-19 18:21:29 +02:00
NetworkStatusIcon . Rotation = 0 ;
NetworkStatusIcon . Source = ImageAwesome . CreateImageSource ( FontAwesomeIcon . Cog , Brushes . DimGray ) ;
NetworkStatusIcon . Spin = true ;
NetworkStatusIcon . SpinDuration = 2 ;
break ;
default :
2023-02-03 15:42:22 +01:00
UpdateText ( text . Get ( TextKey . SystemControl_NetworkDisconnected ) ) ;
2022-04-19 18:21:29 +02:00
NetworkStatusIcon . Source = ImageAwesome . CreateImageSource ( FontAwesomeIcon . Ban , Brushes . DarkOrange ) ;
NetworkStatusIcon . Spin = false ;
WirelessIcon . Child = GetWirelessIcon ( 0 ) ;
break ;
}
2019-03-21 16:05:16 +01:00
}
2023-02-03 15:42:22 +01:00
private void UpdateText ( string text )
{
Button . ToolTip = text ;
Button . SetValue ( System . Windows . Automation . AutomationProperties . NameProperty , text ) ;
}
2022-04-19 18:21:29 +02:00
private UIElement GetWirelessIcon ( int signalStrength )
2019-03-21 16:05:16 +01:00
{
var icon = signalStrength > 66 ? "100" : ( signalStrength > 33 ? "66" : ( signalStrength > 0 ? "33" : "0" ) ) ;
2019-09-04 11:46:30 +02:00
var uri = new Uri ( $"pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/WiFi_{icon}.xaml" ) ;
2019-12-03 15:43:48 +01:00
var resource = new XamlIconResource { Uri = uri } ;
2019-03-21 16:05:16 +01:00
return IconResourceLoader . Load ( resource ) ;
}
}
}