Skip to content

Commit

Permalink
Support CONTENT_APPEND and CONTENT_SHAPE messages; displays table con…
Browse files Browse the repository at this point in the history
…tent via Collection content type
  • Loading branch information
VladimirKhil committed Nov 4, 2023
1 parent 29a1181 commit a4865d2
Show file tree
Hide file tree
Showing 19 changed files with 219 additions and 178 deletions.
6 changes: 4 additions & 2 deletions src/Common/SIStorageService.ViewModel/StorageViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -241,10 +241,12 @@ await Task.WhenAll(
IsLoading = false;
}

LoadPackages(cancellationToken);
await LoadPackagesAsync(cancellationToken);
}

private async void LoadPackages(CancellationToken cancellationToken = default)
private async void LoadPackages(CancellationToken cancellationToken = default) => await LoadPackagesAsync(cancellationToken);

private async Task LoadPackagesAsync(CancellationToken cancellationToken = default)
{
IsLoadingPackages = true;

Expand Down
25 changes: 9 additions & 16 deletions src/Common/SIUI/Behaviors/QuestionReading.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,19 @@ public static class QuestionReading
TextBlock.TextProperty,
typeof(TextBlock));

public static bool GetIsAttached(DependencyObject obj) => (bool)obj.GetValue(IsAttachedProperty);
public static double GetTextSpeed(DependencyObject obj) => (double)obj.GetValue(TextSpeedProperty);

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

// Using a DependencyProperty as the backing store for IsAttached. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsAttachedProperty =
DependencyProperty.RegisterAttached("IsAttached", typeof(bool), typeof(QuestionReading), new PropertyMetadata(false, OnIsAttachedChanged));
public static readonly DependencyProperty TextSpeedProperty =
DependencyProperty.RegisterAttached("TextSpeed", typeof(double), typeof(QuestionReading), new PropertyMetadata(0.0, OnTextSpeedChanged));

public static void OnIsAttachedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
public static void OnTextSpeedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var textBlock = (TextBlock)d;
var tableInfoViewModel = (TableInfoViewModel)textBlock.DataContext;

if ((bool)e.NewValue)
if ((double)e.NewValue > 0)
{
if (tableInfoViewModel.TextSpeed < double.Epsilon)
{
return;
}

textBlock.Loaded += OnLoaded;
textBlock.DataContextChanged += TextBlock_DataContextChanged;
TextProperty.AddValueChanged(textBlock, TextBlock_TextChanged);
Expand Down Expand Up @@ -73,15 +66,15 @@ private static void OnLoaded(object sender, RoutedEventArgs e)

private static void AnimateTextReading(TextBlock textBlock)
{
var tableInfoViewModel = (TableInfoViewModel)textBlock.DataContext;
var textSpeed = GetTextSpeed(textBlock);

textBlock.TextEffects[0].BeginAnimation(
TextEffect.PositionCountProperty,
new Int32Animation
{
From = 0,
To = tableInfoViewModel.Text.Length,
Duration = new Duration(TimeSpan.FromSeconds(tableInfoViewModel.Text.Length * tableInfoViewModel.TextSpeed))
To = textBlock.Text.Length,
Duration = new Duration(TimeSpan.FromSeconds(textBlock.Text.Length * textSpeed))
});
}

Expand Down
8 changes: 3 additions & 5 deletions src/Common/SIUI/Table.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@
Style="{StaticResource QuestionText}"
Margin="10"
TextOptions.TextFormattingMode="Ideal"
lb:QuestionReading.IsAttached="True">
lb:QuestionReading.TextSpeed="{Binding TextSpeed}">
<TextBlock.CacheMode>
<BitmapCache EnableClearType="True" SnapsToDevicePixels="False" RenderAtScale="1.5" />
</TextBlock.CacheMode>
Expand All @@ -463,8 +463,7 @@
TextWrapping="Wrap"
HorizontalAlignment="Left"
TextAlignment="Left"
lb:QuestionReading.IsAttachedPartial="True">

lb:QuestionReading.IsAttachedPartial="True">
<TextBlock.CacheMode>
<BitmapCache EnableClearType="True" SnapsToDevicePixels="False" RenderAtScale="1.5" />
</TextBlock.CacheMode>
Expand Down Expand Up @@ -496,7 +495,7 @@
Style="{StaticResource QuestionText}"
Margin="10"
TextOptions.TextFormattingMode="Ideal"
lb:QuestionReading.IsAttached="True">
lb:QuestionReading.TextSpeed="{Binding DataContext.TextSpeed, RelativeSource={RelativeSource AncestorType=ItemsControl}}">
<TextBlock.CacheMode>
<BitmapCache EnableClearType="True" SnapsToDevicePixels="False" RenderAtScale="1.5" />
</TextBlock.CacheMode>
Expand All @@ -523,7 +522,6 @@
HorizontalAlignment="Left"
TextAlignment="Left"
lb:QuestionReading.IsAttachedPartial="True">

<TextBlock.CacheMode>
<BitmapCache EnableClearType="True" SnapsToDevicePixels="False" RenderAtScale="1.5" />
</TextBlock.CacheMode>
Expand Down
3 changes: 1 addition & 2 deletions src/Common/Utils/Commands/AsyncCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ public bool CanBeExecuted

public bool CanExecute(object? parameter) => _canBeExecuted;

[Obsolete("Use ExecuteAsync instead")]
public async void Execute(object? parameter) => await _execute(parameter); // TODO: throw NotSupported because `async void` is a bad practice
public void Execute(object? parameter) => _execute(parameter);

public Task ExecuteAsync(object? parameter) => _execute(parameter);
}
48 changes: 48 additions & 0 deletions src/Common/Utils/Commands/AsyncContextCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System.Windows.Input;

namespace Utils.Commands;

/// <summary>
/// Describes an asynchronous command that can be executed only in specified context.
/// </summary>
public sealed class AsyncContextCommand : ICommand
{
private readonly Func<object?, Task> _execute;

/// <summary>
/// Valid execution context.
/// </summary>
public HashSet<object> ExecutionContext { get; } = new();

public event EventHandler? CanExecuteChanged;

public AsyncContextCommand(Func<object?, Task> execute) => _execute = execute ?? throw new ArgumentNullException(nameof(execute));

/// <summary>
/// Raises <see cref="CanExecuteChanged" /> event in a synchronization context-bound thread.
/// </summary>
public void OnCanBeExecutedChanged()
{
if (CanExecuteChanged != null)
{
if (SynchronizationContext.Current == null && UI.Scheduler != null)
{
Task.Factory.StartNew(
() => CanExecuteChanged(this, EventArgs.Empty),
CancellationToken.None,
TaskCreationOptions.None,
UI.Scheduler);
}
else
{
CanExecuteChanged(this, EventArgs.Empty);
}
}
}

public bool CanExecute(object? parameter) => parameter != null && ExecutionContext.Contains(parameter);

public void Execute(object? parameter) => _execute(parameter);

public Task ExecuteAsync(object? parameter) => _execute(parameter);
}
6 changes: 4 additions & 2 deletions src/SICore/SICore/Clients/Game/GameLogic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,9 @@ internal void OnContentScreenText(string text, bool waitForFinish, TimeSpan dura
// Real question text is sent later and it sequentially replaces test shape
// Text shape is required to display partial question on the screen correctly
// (font size and number of lines must be calculated in the beginning to prevent UI flickers on question text growth)
_gameActions.SendMessageWithArgs(Messages.TextShape, Regex.Replace(text, "[^\r\n\t\f ]", "и"));
var shape = Regex.Replace(text, "[^\r\n\t\f ]", "и");
_gameActions.SendMessageWithArgs(Messages.TextShape, shape);
_gameActions.SendMessageWithArgs(Messages.ContentShape, ContentPlacements.Screen, 0, ContentTypes.Text, shape);

_data.Text = text;
_data.TextLength = 0;
Expand Down Expand Up @@ -2727,7 +2729,7 @@ private void PrintPartial()

var subText = text.Substring(_data.TextLength, printingLength);

_gameActions.SendMessageWithArgs(Messages.Content, ContentPlacements.Screen, 0, Constants.PartialText, subText.EscapeNewLines());
_gameActions.SendMessageWithArgs(Messages.ContentAppend, ContentPlacements.Screen, 0, ContentTypes.Text, subText.EscapeNewLines());
_gameActions.SendMessageWithArgs(Messages.Atom, Constants.PartialText, subText);
_gameActions.SystemReplic(subText);

Expand Down
8 changes: 6 additions & 2 deletions src/SICore/SICore/Clients/Viewer/IViewerLogic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,13 @@ public interface IViewerLogic : ILogic
/// <summary>
/// Question fragment received.
/// </summary>
[Obsolete]
void OnScreenContent(string[] mparams);

/// <summary>
/// Question background fragment received.
/// </summary>
[Obsolete]
void OnBackgroundContent(string[] mparams);

void SetRight(string answer);
Expand Down Expand Up @@ -83,9 +85,9 @@ public interface IViewerLogic : ILogic
void Person(int playerIndex, bool isRight);

/// <summary>
/// Известен тип вопроса
/// Handles question start.
/// </summary>
void OnQuestionType();
void OnQuestionStart();

/// <summary>
/// Завершение раунда
Expand Down Expand Up @@ -177,4 +179,6 @@ void ResetPlayers() { }
void OnAnswerOptions(int optionCount) { }

void OnContent(string[] mparams) { }

void OnContentAppend(string[] mparams) { }
}
12 changes: 6 additions & 6 deletions src/SICore/SICore/Clients/Viewer/Viewer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,11 @@ await _client.Node.ConnectionsLock.WithLockAsync(() =>
_logic.OnContent(mparams);
break;

case Messages.ContentAppend:
_ignoreAtoms = true;
_logic.OnContentAppend(mparams);
break;

case Messages.Atom_Hint:
if (mparams.Length > 1)
{
Expand Down Expand Up @@ -985,9 +990,6 @@ await _client.Node.ConnectionsLock.WithLockAsync(() =>
ClientData.Players[i].InGame = i + 1 < mparams.Length && mparams[i + 1] == "+";
}

ClientData.AtomIndex = -1;
ClientData.IsPartial = false;

#endregion
break;
}
Expand Down Expand Up @@ -1112,11 +1114,9 @@ private void OnSetJoinMode(string[] mparams)
private void OnQuestionType(string[] mparams)
{
ClientData.AtomType = AtomTypes.Text;
ClientData.AtomIndex = -1;
ClientData.IsPartial = false;
ClientData.QuestionType = mparams[1];

_logic.OnQuestionType();
_logic.OnQuestionStart();
}

private void OnChoice(string[] mparams)
Expand Down
2 changes: 1 addition & 1 deletion src/SICore/SICore/Clients/Viewer/ViewerComputerLogic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ public virtual void Person(int playerIndex, bool isRight)

}

public void OnQuestionType()
public void OnQuestionStart()
{

}
Expand Down
11 changes: 2 additions & 9 deletions src/SICore/SICore/Clients/Viewer/ViewerData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,15 +209,8 @@ public string StageName
/// </summary>
public string QuestionType { get; set; }

public bool IsPartial { get; set; }

public string AtomType { get; set; } = "";

/// <summary>
/// Номер текущего атома сценария вопроса
/// </summary>
public int AtomIndex { get; set; }

internal int Winner { get; set; }

internal int LastStakerIndex { get; set; } = -1;
Expand Down Expand Up @@ -615,9 +608,9 @@ public string HostName
}

/// <summary>
/// External media uri.
/// External content that can be loaded only after user approval.
/// </summary>
public string ExternalUri { get; internal set; }
public List<(string ContentType, string Uri)> ExternalContent { get; } = new();

private string[] _roundNames = Array.Empty<string>();

Expand Down
Loading

0 comments on commit a4865d2

Please sign in to comment.