Skip to content

Commit

Permalink
SImulator: introduce web view support; allow to control media at askA…
Browse files Browse the repository at this point in the history
…nswer stage
  • Loading branch information
VladimirKhil committed Jan 28, 2024
1 parent 3c2f79b commit e3305c6
Show file tree
Hide file tree
Showing 29 changed files with 358 additions and 108 deletions.
19 changes: 3 additions & 16 deletions src/Common/SIUI/Table.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -721,26 +721,13 @@
<Grid.RowDefinitions>
<RowDefinition
Height="{Binding LostButtonPlayers.Count, Converter={StaticResource PressedTopRowHeightConverter}}" />

<RowDefinition Height="*" />

<RowDefinition
Height="{Binding LostButtonPlayers.Count, Converter={StaticResource PressedBottomRowHeightConverter}}" />
</Grid.RowDefinitions>

<Border
Grid.Row="1"
Background="{Binding Settings.Model.AnswererColorString}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<ContentControl>
<TextBlock
Style="{StaticResource CenteredText}"
lb:FillManager.Fill="True"
Text="{Binding ActivePlayer}" />
</ContentControl>
</Border>


<ItemsControl ItemsSource="{Binding LostButtonPlayers}" Grid.Row="2">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
Expand Down
22 changes: 22 additions & 0 deletions src/SImulator/SImulator.ViewModel/Contracts/IDisplayDescriptor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace SImulator.ViewModel.Contracts;

/// <summary>
/// Provides display info.
/// </summary>
public interface IDisplayDescriptor
{
/// <summary>
/// Display name.
/// </summary>
string Name { get; }

/// <summary>
/// Full screen marker.
/// </summary>
bool IsFullScreen { get; }

/// <summary>
/// Should the screen display a web UI.
/// </summary>
bool IsWebView => false;
}
6 changes: 6 additions & 0 deletions src/SImulator/SImulator.ViewModel/Contracts/IWebInterop.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace SImulator.ViewModel.Contracts;

public interface IWebInterop
{
event Action<string> SendJsonMessage;
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,12 @@ public void OnAskAnswer(string mode)
return;
}

GameViewModel.ActiveMediaCommand = null;
// Disabled for run timer command so in false start mode when host enables buttons before media finishes it is still possible to control media being played
// Consider later will this lead to playing issues
if (GameViewModel.ActiveMediaCommand == GameViewModel.StopMediaTimer)
{
GameViewModel.ActiveMediaCommand = null;
}

switch (mode)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ namespace SImulator.ViewModel.Controllers;
/// <inheritdoc cref="IPresentationController" />
public sealed class PresentationController : IPresentationController, INotifyPropertyChanged
{
public Uri Source { get; } = new($"file:///{AppDomain.CurrentDomain.BaseDirectory}webtable/index.html");

private int _previousCode = -1;

private IAnimatableTimer _animatableTimer = PlatformManager.Instance.CreateAnimatableTimer();
private readonly IAnimatableTimer _animatableTimer = PlatformManager.Instance.CreateAnimatableTimer();

private IPresentationListener? _listener;

Expand Down Expand Up @@ -52,7 +54,7 @@ internal IPresentationListener? Listener

private bool _stageCallbackBlock = false;

public int ScreenIndex { get; set; }
public IDisplayDescriptor Screen { get; }

public event Action<Exception>? Error;

Expand All @@ -68,8 +70,10 @@ public bool ShowPlayers
set { if (_showPlayers != value) { _showPlayers = value; OnPropertyChanged(); } }
}

public PresentationController()
public PresentationController(IDisplayDescriptor screen)
{
Screen = screen;

TInfo = new TableInfoViewModel
{
Enabled = true,
Expand Down Expand Up @@ -165,7 +169,7 @@ private void SoundFinished()

public async void Start()
{
await PlatformManager.Instance.CreateMainViewAsync(this, ScreenIndex);
await PlatformManager.Instance.CreateMainViewAsync(this, Screen);
TInfo.TStage = TableStage.Sign;
}

Expand Down
12 changes: 0 additions & 12 deletions src/SImulator/SImulator.ViewModel/PlatformSpecific/IScreen.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using SImulator.ViewModel.Core;
using SImulator.ViewModel.Contracts;
using SImulator.ViewModel.Core;
using SImulator.ViewModel.Model;
using Utils.Timers;

Expand All @@ -22,11 +23,11 @@ protected PlatformManager()

public abstract void ClosePlayersView();

public abstract Task CreateMainViewAsync(object dataContext, int screenNumber);
public abstract Task CreateMainViewAsync(object dataContext, IDisplayDescriptor screen);

public abstract Task CloseMainViewAsync();

public abstract IScreen[] GetScreens();
public abstract IDisplayDescriptor[] GetScreens();

public abstract string[] GetLocalComputers();

Expand All @@ -52,7 +53,7 @@ protected PlatformManager()

public abstract void PlaySound(string name, Action onFinish);

public abstract IGameLogger CreateLogger(string? folder);
public abstract IGameLogger CreateGameLogger(string? folder);

public abstract void ClearMedia();

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/SImulator/SImulator.ViewModel/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@
<data name="GameStartError" xml:space="preserve">
<value>Ошибка старта игры: {0}</value>
</data>
<data name="IpAddressHint" xml:space="preserve">
<value>[Ваш IP-адрес]</value>
</data>
<data name="LoggerCreationWarning" xml:space="preserve">
<value>Ошибка создания файла лога: {0}. Лог записываться не будет</value>
</data>
Expand Down
52 changes: 28 additions & 24 deletions src/SImulator/SImulator.ViewModel/ViewModel/MainViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using SIEngine;
using SImulator.ViewModel.ButtonManagers;
using SImulator.ViewModel.Contracts;
using SImulator.ViewModel.Controllers;
using SImulator.ViewModel.Core;
using SImulator.ViewModel.Listeners;
Expand Down Expand Up @@ -121,24 +122,18 @@ public bool IsStarting

public AppSettingsViewModel SettingsViewModel { get; }

private string[] _comPorts;
private readonly Lazy<string[]> _comPorts;

public string[] ComPorts
private string[] LoadComPorts()
{
get
{
if (_comPorts == null)
{
_comPorts = PlatformManager.Instance.GetComPorts();
var ports = PlatformManager.Instance.GetComPorts();

if (Settings.ComPort == null || _comPorts != null && _comPorts.Length > 0)
{
Settings.ComPort = _comPorts[0];
}
}

return _comPorts;
if (Settings.ComPort == null || _comPorts != null && ports.Length > 0)
{
Settings.ComPort = ports[0];
}

return ports;
}

private GameViewModel? _game;
Expand Down Expand Up @@ -182,9 +177,9 @@ public ModeTransition Transition

public bool CanSelectScreens => (_mode == GameMode.Start) && Screens.Length > 1;

public IScreen[] Screens { get; private set; }
public IDisplayDescriptor[] Screens { get; private set; }

public string Host => "[Ваш IP-адрес]";
public string Host => Resources.IpAddressHint;

/// <summary>
/// Список игроков, отображаемых на табло в особом режиме игры
Expand Down Expand Up @@ -231,7 +226,8 @@ public MainViewModel(AppSettings settings)
Players = new ObservableCollection<SimplePlayerInfo>();

Screens = PlatformManager.Instance.GetScreens();

_comPorts = new Lazy<string[]>(LoadComPorts);

var screensLength = Screens.Length;

#if DEBUG
Expand Down Expand Up @@ -386,24 +382,24 @@ private IGameLogger CreateLogger()
if (string.IsNullOrWhiteSpace(logsFolder))
{
PlatformManager.Instance.ShowMessage(Resources.LogsFolderNotSetWarning);
return PlatformManager.Instance.CreateLogger(null);
return PlatformManager.Instance.CreateGameLogger(null);
}
else
{
try
{
return PlatformManager.Instance.CreateLogger(logsFolder);
return PlatformManager.Instance.CreateGameLogger(logsFolder);
}
catch (Exception exc)
{
PlatformManager.Instance.ShowMessage(string.Format(Resources.LoggerCreationWarning, exc.Message), false);
return PlatformManager.Instance.CreateLogger(null);
return PlatformManager.Instance.CreateGameLogger(null);
}
}
}
else
{
return PlatformManager.Instance.CreateLogger(null);
return PlatformManager.Instance.CreateGameLogger(null);
}
}

Expand All @@ -414,6 +410,15 @@ private async Task Start_Executed(object? _)
{
try
{
var screenIndex = SettingsViewModel.Model.ScreenNumber;

if (screenIndex < 0 || screenIndex >= Screens.Length)
{
return;
}

var screen = Screens[screenIndex];

_start.CanBeExecuted = false;
IsStarting = true;

Expand Down Expand Up @@ -441,10 +446,9 @@ private async Task Start_Executed(object? _)

var presentationListener = new PresentationListener(engine);

var presentationController = new PresentationController
var presentationController = new PresentationController(screen)
{
Listener = presentationListener,
ScreenIndex = SettingsViewModel.Model.ScreenNumber
Listener = presentationListener
};

presentationController.UpdateSettings(SettingsViewModel.SIUISettings.Model);
Expand Down
83 changes: 83 additions & 0 deletions src/SImulator/SImulator/Behaviors/WebView2Behavior.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using Microsoft.Web.WebView2.Core;
using Microsoft.Web.WebView2.Wpf;
using SImulator.ViewModel.Contracts;
using System;
using System.Diagnostics;
using System.Windows;

namespace SImulator.Behaviors;

/// <summary>
/// Attaches additional behavior for WebView2 control.
/// </summary>
internal static class WebView2Behavior
{
public static bool GetIsAttached(DependencyObject obj) => (bool)obj.GetValue(IsAttachedProperty);

public static void SetIsAttached(DependencyObject obj, bool value) => obj.SetValue(IsAttachedProperty, value);

public static readonly DependencyProperty IsAttachedProperty =
DependencyProperty.RegisterAttached("IsAttached", typeof(bool), typeof(WebView2), new PropertyMetadata(false, OnIsAttachedChanged));

public static void OnIsAttachedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!(bool)e.NewValue)
{
return;
}

var webView2 = (WebView2)d;

UpdateWebView2Environment(webView2);

var coreWebView = webView2.CoreWebView2;

webView2.Unloaded += WebView2_Unloaded;
}

private static void WebView2_Unloaded(object sender, RoutedEventArgs e)
{
var webView2 = (WebView2)sender;

if (webView2 == null)
{
return;
}

webView2.Unloaded -= WebView2_Unloaded;

var coreWebView = webView2.CoreWebView2;

if (coreWebView != null)
{
// Prevent WebView for producing sound after unload
coreWebView.IsMuted = true;

if (webView2.DataContext is IWebInterop webInterop)
{
webInterop.SendJsonMessage -= coreWebView.PostWebMessageAsJson;
}
}
}

private static async void UpdateWebView2Environment(WebView2 webView2)
{
try
{
// Allowing autoplay
var options = new CoreWebView2EnvironmentOptions("--autoplay-policy=no-user-gesture-required");
var environment = await CoreWebView2Environment.CreateAsync(null, null, options);

await webView2.EnsureCoreWebView2Async(environment);

if (webView2.DataContext is IWebInterop webInterop)
{
webInterop.SendJsonMessage += webView2.CoreWebView2.PostWebMessageAsJson;
}
}
catch (Exception exc)
{
Trace.TraceError(exc.ToString());
}
}
}
Loading

0 comments on commit e3305c6

Please sign in to comment.