Restore playback countdown display
This commit is contained in:
@@ -46,6 +46,61 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
<Border
|
||||||
|
Padding="14,12"
|
||||||
|
Background="#251A0B"
|
||||||
|
BorderBrush="{StaticResource ControlRoomSignalAmberBrush}"
|
||||||
|
BorderThickness="2"
|
||||||
|
CornerRadius="18"
|
||||||
|
Visibility="{x:Bind ViewModel.PlaybackCountdownVisibility, Mode=OneWay}">
|
||||||
|
<Grid ColumnSpacing="14">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Border
|
||||||
|
Width="54"
|
||||||
|
Height="54"
|
||||||
|
Background="#33FFB81C"
|
||||||
|
BorderBrush="{StaticResource ControlRoomSignalAmberBrush}"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="27">
|
||||||
|
<SymbolIcon
|
||||||
|
Foreground="{StaticResource ControlRoomSignalAmberBrush}"
|
||||||
|
Symbol="Clock"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<StackPanel Grid.Column="1" Spacing="6">
|
||||||
|
<Grid ColumnSpacing="12">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
FontFamily="Consolas"
|
||||||
|
FontSize="30"
|
||||||
|
Foreground="{StaticResource ControlRoomTextPrimaryBrush}"
|
||||||
|
Text="{x:Bind ViewModel.PlaybackCountdownText, Mode=OneWay}" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="1"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ConsoleBodyTextStyle}"
|
||||||
|
Text="{x:Bind ViewModel.PlaybackCountdownDetail, Mode=OneWay}"
|
||||||
|
TextTrimming="CharacterEllipsis" />
|
||||||
|
</Grid>
|
||||||
|
<ProgressBar
|
||||||
|
Height="8"
|
||||||
|
Maximum="100"
|
||||||
|
Minimum="0"
|
||||||
|
Value="{x:Bind ViewModel.PlaybackCountdownProgress, Mode=OneWay}" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
<Grid ColumnSpacing="12">
|
<Grid ColumnSpacing="12">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="1.25*" />
|
<ColumnDefinition Width="1.25*" />
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ public sealed class ChannelScheduleItem : ObservableObject
|
|||||||
private ImageSource? _internalNextPreviewSource;
|
private ImageSource? _internalNextPreviewSource;
|
||||||
private string _internalNextPreviewStatusLabel = string.Empty;
|
private string _internalNextPreviewStatusLabel = string.Empty;
|
||||||
private string _internalNextPreviewDisplayName = string.Empty;
|
private string _internalNextPreviewDisplayName = string.Empty;
|
||||||
|
private double _playbackRemainingSeconds;
|
||||||
|
private double _playbackTotalSeconds;
|
||||||
|
|
||||||
public Guid Id { get; set; } = Guid.NewGuid();
|
public Guid Id { get; set; } = Guid.NewGuid();
|
||||||
|
|
||||||
@@ -105,6 +107,7 @@ public sealed class ChannelScheduleItem : ObservableObject
|
|||||||
OnPropertyChanged(nameof(StateBadgeBackgroundBrush));
|
OnPropertyChanged(nameof(StateBadgeBackgroundBrush));
|
||||||
OnPropertyChanged(nameof(CardOpacity));
|
OnPropertyChanged(nameof(CardOpacity));
|
||||||
OnPropertyChanged(nameof(CanDelete));
|
OnPropertyChanged(nameof(CanDelete));
|
||||||
|
OnPropertyChanged(nameof(PlaybackCountdownVisibility));
|
||||||
OnIssueStateChanged();
|
OnIssueStateChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -307,6 +310,27 @@ public sealed class ChannelScheduleItem : ObservableObject
|
|||||||
? "실데이터 프리뷰 준비 중"
|
? "실데이터 프리뷰 준비 중"
|
||||||
: _renderedPreviewStatusLabel;
|
: _renderedPreviewStatusLabel;
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public bool HasPlaybackCountdown => State == ScheduleQueueItemState.OnAir && _playbackTotalSeconds > 0;
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public Visibility PlaybackCountdownVisibility => HasPlaybackCountdown ? Visibility.Visible : Visibility.Collapsed;
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public string PlaybackCountdownText => HasPlaybackCountdown
|
||||||
|
? $"다음 컷까지 {Math.Max(0, (int)Math.Ceiling(_playbackRemainingSeconds))}초"
|
||||||
|
: "대기 중";
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public string PlaybackCountdownDetail => HasPlaybackCountdown
|
||||||
|
? $"{FormatName} / {DisplayRegionLabel}"
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public double PlaybackCountdownProgress => HasPlaybackCountdown
|
||||||
|
? Math.Clamp((_playbackRemainingSeconds / _playbackTotalSeconds) * 100d, 0d, 100d)
|
||||||
|
: 0d;
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public ImageSource? InternalNextPreviewSource => _internalNextPreviewSource;
|
public ImageSource? InternalNextPreviewSource => _internalNextPreviewSource;
|
||||||
|
|
||||||
@@ -403,6 +427,33 @@ public sealed class ChannelScheduleItem : ObservableObject
|
|||||||
OnInternalNextPreviewChanged();
|
OnInternalNextPreviewChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdatePlaybackCountdown(TimeSpan remaining, TimeSpan total)
|
||||||
|
{
|
||||||
|
var normalizedTotal = Math.Max(0, total.TotalSeconds);
|
||||||
|
var normalizedRemaining = Math.Clamp(remaining.TotalSeconds, 0, normalizedTotal);
|
||||||
|
if (Math.Abs(_playbackRemainingSeconds - normalizedRemaining) < 0.001d &&
|
||||||
|
Math.Abs(_playbackTotalSeconds - normalizedTotal) < 0.001d)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_playbackRemainingSeconds = normalizedRemaining;
|
||||||
|
_playbackTotalSeconds = normalizedTotal;
|
||||||
|
OnPlaybackCountdownChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearPlaybackCountdown()
|
||||||
|
{
|
||||||
|
if (_playbackRemainingSeconds <= 0 && _playbackTotalSeconds <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_playbackRemainingSeconds = 0;
|
||||||
|
_playbackTotalSeconds = 0;
|
||||||
|
OnPlaybackCountdownChanged();
|
||||||
|
}
|
||||||
|
|
||||||
public void UpdateThumbnailLayout(ThumbnailDisplayMetrics metrics)
|
public void UpdateThumbnailLayout(ThumbnailDisplayMetrics metrics)
|
||||||
{
|
{
|
||||||
ThumbnailWidth = metrics.Width;
|
ThumbnailWidth = metrics.Width;
|
||||||
@@ -453,6 +504,15 @@ public sealed class ChannelScheduleItem : ObservableObject
|
|||||||
OnPropertyChanged(nameof(InternalNextPreviewDisplayName));
|
OnPropertyChanged(nameof(InternalNextPreviewDisplayName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnPlaybackCountdownChanged()
|
||||||
|
{
|
||||||
|
OnPropertyChanged(nameof(HasPlaybackCountdown));
|
||||||
|
OnPropertyChanged(nameof(PlaybackCountdownVisibility));
|
||||||
|
OnPropertyChanged(nameof(PlaybackCountdownText));
|
||||||
|
OnPropertyChanged(nameof(PlaybackCountdownDetail));
|
||||||
|
OnPropertyChanged(nameof(PlaybackCountdownProgress));
|
||||||
|
}
|
||||||
|
|
||||||
public static ChannelScheduleItem FromTemplate(FormatTemplateDefinition template, ScheduleRegionOption? regionOption = null)
|
public static ChannelScheduleItem FromTemplate(FormatTemplateDefinition template, ScheduleRegionOption? regionOption = null)
|
||||||
{
|
{
|
||||||
var selectedRegion = regionOption ?? new ScheduleRegionOption
|
var selectedRegion = regionOption ?? new ScheduleRegionOption
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ public sealed class ChannelScheduleEngine
|
|||||||
item.CurrentRegionLabel = string.Empty;
|
item.CurrentRegionLabel = string.Empty;
|
||||||
item.ClearRenderedPreview();
|
item.ClearRenderedPreview();
|
||||||
item.ClearInternalNextPreview();
|
item.ClearInternalNextPreview();
|
||||||
|
item.ClearPlaybackCountdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
_lastPlaybackItemId = null;
|
_lastPlaybackItemId = null;
|
||||||
@@ -203,6 +204,7 @@ public sealed class ChannelScheduleEngine
|
|||||||
|
|
||||||
item.State = ScheduleQueueItemState.Queued;
|
item.State = ScheduleQueueItemState.Queued;
|
||||||
item.CurrentRegionLabel = string.Empty;
|
item.CurrentRegionLabel = string.Empty;
|
||||||
|
item.ClearPlaybackCountdown();
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -221,6 +223,7 @@ public sealed class ChannelScheduleEngine
|
|||||||
_directPlaybackItem.CurrentRegionLabel = string.Empty;
|
_directPlaybackItem.CurrentRegionLabel = string.Empty;
|
||||||
_directPlaybackItem.ClearRenderedPreview();
|
_directPlaybackItem.ClearRenderedPreview();
|
||||||
_directPlaybackItem.ClearInternalNextPreview();
|
_directPlaybackItem.ClearInternalNextPreview();
|
||||||
|
_directPlaybackItem.ClearPlaybackCountdown();
|
||||||
_directPlaybackItem = null;
|
_directPlaybackItem = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,6 +247,7 @@ public sealed class ChannelScheduleEngine
|
|||||||
{
|
{
|
||||||
item.State = ScheduleQueueItemState.Queued;
|
item.State = ScheduleQueueItemState.Queued;
|
||||||
item.CurrentRegionLabel = string.Empty;
|
item.CurrentRegionLabel = string.Empty;
|
||||||
|
item.ClearPlaybackCountdown();
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -264,6 +268,7 @@ public sealed class ChannelScheduleEngine
|
|||||||
item.CurrentRegionLabel = string.Empty;
|
item.CurrentRegionLabel = string.Empty;
|
||||||
item.ClearRenderedPreview();
|
item.ClearRenderedPreview();
|
||||||
item.ClearInternalNextPreview();
|
item.ClearInternalNextPreview();
|
||||||
|
item.ClearPlaybackCountdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
RefreshQueueMarkers();
|
RefreshQueueMarkers();
|
||||||
@@ -281,6 +286,7 @@ public sealed class ChannelScheduleEngine
|
|||||||
item.CurrentRegionLabel = string.Empty;
|
item.CurrentRegionLabel = string.Empty;
|
||||||
item.ClearRenderedPreview();
|
item.ClearRenderedPreview();
|
||||||
item.ClearInternalNextPreview();
|
item.ClearInternalNextPreview();
|
||||||
|
item.ClearPlaybackCountdown();
|
||||||
RefreshQueueMarkers();
|
RefreshQueueMarkers();
|
||||||
QueueChanged?.Invoke(this, EventArgs.Empty);
|
QueueChanged?.Invoke(this, EventArgs.Empty);
|
||||||
return true;
|
return true;
|
||||||
@@ -312,6 +318,7 @@ public sealed class ChannelScheduleEngine
|
|||||||
activeItem.LastError = string.Empty;
|
activeItem.LastError = string.Empty;
|
||||||
activeItem.CurrentRegionLabel = string.Empty;
|
activeItem.CurrentRegionLabel = string.Empty;
|
||||||
activeItem.ClearInternalNextPreview();
|
activeItem.ClearInternalNextPreview();
|
||||||
|
activeItem.ClearPlaybackCountdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
RefreshQueueMarkers();
|
RefreshQueueMarkers();
|
||||||
@@ -449,6 +456,7 @@ public sealed class ChannelScheduleEngine
|
|||||||
sendingItem.LastError = ex.Message;
|
sendingItem.LastError = ex.Message;
|
||||||
sendingItem.CurrentRegionLabel = string.Empty;
|
sendingItem.CurrentRegionLabel = string.Empty;
|
||||||
sendingItem.ClearInternalNextPreview();
|
sendingItem.ClearInternalNextPreview();
|
||||||
|
sendingItem.ClearPlaybackCountdown();
|
||||||
ClearSkipCurrentItem(sendingItem);
|
ClearSkipCurrentItem(sendingItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -628,6 +636,7 @@ public sealed class ChannelScheduleEngine
|
|||||||
|
|
||||||
queueItem.CurrentRegionLabel = string.Empty;
|
queueItem.CurrentRegionLabel = string.Empty;
|
||||||
queueItem.ClearInternalNextPreview();
|
queueItem.ClearInternalNextPreview();
|
||||||
|
queueItem.ClearPlaybackCountdown();
|
||||||
_lastPlaybackItemId = queueItem.Id;
|
_lastPlaybackItemId = queueItem.Id;
|
||||||
if (playedAny)
|
if (playedAny)
|
||||||
{
|
{
|
||||||
@@ -727,6 +736,7 @@ public sealed class ChannelScheduleEngine
|
|||||||
|
|
||||||
queueItem.CurrentRegionLabel = string.Empty;
|
queueItem.CurrentRegionLabel = string.Empty;
|
||||||
queueItem.ClearInternalNextPreview();
|
queueItem.ClearInternalNextPreview();
|
||||||
|
queueItem.ClearPlaybackCountdown();
|
||||||
_lastPlaybackItemId = queueItem.Id;
|
_lastPlaybackItemId = queueItem.Id;
|
||||||
if (playedAny)
|
if (playedAny)
|
||||||
{
|
{
|
||||||
@@ -758,6 +768,7 @@ public sealed class ChannelScheduleEngine
|
|||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
queueItem.State = ScheduleQueueItemState.Sending;
|
queueItem.State = ScheduleQueueItemState.Sending;
|
||||||
|
queueItem.ClearPlaybackCountdown();
|
||||||
RefreshQueueMarkers();
|
RefreshQueueMarkers();
|
||||||
QueueChanged?.Invoke(this, EventArgs.Empty);
|
QueueChanged?.Invoke(this, EventArgs.Empty);
|
||||||
|
|
||||||
@@ -780,8 +791,11 @@ public sealed class ChannelScheduleEngine
|
|||||||
await _adapter.TakeAsync(Channel, cancellationToken).ConfigureAwait(false);
|
await _adapter.TakeAsync(Channel, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var onAirAt = DateTimeOffset.Now;
|
var onAirAt = DateTimeOffset.Now;
|
||||||
|
var durationSeconds = ScheduleTemplatePolicy.NormalizeCutDurationSeconds(cut.DurationSeconds, template);
|
||||||
|
var playbackDuration = TimeSpan.FromSeconds(durationSeconds);
|
||||||
queueItem.State = ScheduleQueueItemState.OnAir;
|
queueItem.State = ScheduleQueueItemState.OnAir;
|
||||||
queueItem.LastPlayedAt = onAirAt;
|
queueItem.LastPlayedAt = onAirAt;
|
||||||
|
queueItem.UpdatePlaybackCountdown(playbackDuration, playbackDuration);
|
||||||
RefreshQueueMarkers();
|
RefreshQueueMarkers();
|
||||||
QueueChanged?.Invoke(this, EventArgs.Empty);
|
QueueChanged?.Invoke(this, EventArgs.Empty);
|
||||||
|
|
||||||
@@ -792,8 +806,6 @@ public sealed class ChannelScheduleEngine
|
|||||||
signal.TrySetResult(true);
|
signal.TrySetResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
var durationSeconds = ScheduleTemplatePolicy.NormalizeCutDurationSeconds(cut.DurationSeconds, template);
|
|
||||||
var playbackDuration = TimeSpan.FromSeconds(durationSeconds);
|
|
||||||
await CaptureCurrentPreviewAsync(queueItem, template, cancellationToken).ConfigureAwait(false);
|
await CaptureCurrentPreviewAsync(queueItem, template, cancellationToken).ConfigureAwait(false);
|
||||||
QueueChanged?.Invoke(this, EventArgs.Empty);
|
QueueChanged?.Invoke(this, EventArgs.Empty);
|
||||||
if (!ShouldSkipCurrentItem(queueItem))
|
if (!ShouldSkipCurrentItem(queueItem))
|
||||||
@@ -829,17 +841,51 @@ public sealed class ChannelScheduleEngine
|
|||||||
|
|
||||||
if (ShouldSkipCurrentItem(queueItem))
|
if (ShouldSkipCurrentItem(queueItem))
|
||||||
{
|
{
|
||||||
|
queueItem.ClearPlaybackCountdown();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var remainingDuration = playbackDuration - (DateTimeOffset.Now - onAirAt);
|
var remainingDuration = playbackDuration - (DateTimeOffset.Now - onAirAt);
|
||||||
if (remainingDuration <= TimeSpan.Zero)
|
if (remainingDuration <= TimeSpan.Zero)
|
||||||
{
|
{
|
||||||
|
queueItem.ClearPlaybackCountdown();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var delayTask = Task.Delay(remainingDuration, cancellationToken);
|
await WaitForPlaybackCountdownAsync(queueItem, onAirAt, playbackDuration, signal, cancellationToken)
|
||||||
await Task.WhenAny(delayTask, signal.Task).ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task WaitForPlaybackCountdownAsync(
|
||||||
|
ChannelScheduleItem queueItem,
|
||||||
|
DateTimeOffset onAirAt,
|
||||||
|
TimeSpan playbackDuration,
|
||||||
|
TaskCompletionSource<bool> advanceSignal,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
while (!cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
var remaining = playbackDuration - (DateTimeOffset.Now - onAirAt);
|
||||||
|
if (remaining <= TimeSpan.Zero)
|
||||||
|
{
|
||||||
|
queueItem.ClearPlaybackCountdown();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
queueItem.UpdatePlaybackCountdown(remaining, playbackDuration);
|
||||||
|
var updateInterval = remaining > TimeSpan.FromSeconds(1)
|
||||||
|
? TimeSpan.FromSeconds(1)
|
||||||
|
: remaining;
|
||||||
|
var delayTask = Task.Delay(updateInterval, cancellationToken);
|
||||||
|
var completedTask = await Task.WhenAny(delayTask, advanceSignal.Task).ConfigureAwait(false);
|
||||||
|
if (completedTask == advanceSignal.Task)
|
||||||
|
{
|
||||||
|
queueItem.ClearPlaybackCountdown();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
queueItem.ClearPlaybackCountdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task CaptureCurrentPreviewAsync(
|
private async Task CaptureCurrentPreviewAsync(
|
||||||
@@ -1215,6 +1261,7 @@ public sealed class ChannelScheduleEngine
|
|||||||
preparedFrame.Item.CurrentRegionLabel = string.Empty;
|
preparedFrame.Item.CurrentRegionLabel = string.Empty;
|
||||||
preparedFrame.Item.ClearRenderedPreview();
|
preparedFrame.Item.ClearRenderedPreview();
|
||||||
preparedFrame.Item.ClearInternalNextPreview();
|
preparedFrame.Item.ClearInternalNextPreview();
|
||||||
|
preparedFrame.Item.ClearPlaybackCountdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClearSkipCurrentItem(ChannelScheduleItem queueItem)
|
private void ClearSkipCurrentItem(ChannelScheduleItem queueItem)
|
||||||
@@ -1732,6 +1779,7 @@ public sealed class ChannelScheduleEngine
|
|||||||
item.CurrentRegionLabel = string.Empty;
|
item.CurrentRegionLabel = string.Empty;
|
||||||
item.ClearRenderedPreview();
|
item.ClearRenderedPreview();
|
||||||
item.ClearInternalNextPreview();
|
item.ClearInternalNextPreview();
|
||||||
|
item.ClearPlaybackCountdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1742,6 +1790,7 @@ public sealed class ChannelScheduleEngine
|
|||||||
queueItem.CurrentRegionLabel = string.Empty;
|
queueItem.CurrentRegionLabel = string.Empty;
|
||||||
queueItem.ClearRenderedPreview();
|
queueItem.ClearRenderedPreview();
|
||||||
queueItem.ClearInternalNextPreview();
|
queueItem.ClearInternalNextPreview();
|
||||||
|
queueItem.ClearPlaybackCountdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string NormalizeDataUnavailableReason(string reason)
|
private static string NormalizeDataUnavailableReason(string reason)
|
||||||
|
|||||||
@@ -372,6 +372,15 @@ public sealed class ChannelScheduleViewModel : ObservableObject
|
|||||||
?? QueueNextPlaybackItem?.PreviewStatusLabel
|
?? QueueNextPlaybackItem?.PreviewStatusLabel
|
||||||
?? "다음 컷 없음";
|
?? "다음 컷 없음";
|
||||||
|
|
||||||
|
public Visibility PlaybackCountdownVisibility =>
|
||||||
|
CurrentPlaybackItem?.PlaybackCountdownVisibility ?? Visibility.Collapsed;
|
||||||
|
|
||||||
|
public string PlaybackCountdownText => CurrentPlaybackItem?.PlaybackCountdownText ?? "대기 중";
|
||||||
|
|
||||||
|
public string PlaybackCountdownDetail => CurrentPlaybackItem?.PlaybackCountdownDetail ?? string.Empty;
|
||||||
|
|
||||||
|
public double PlaybackCountdownProgress => CurrentPlaybackItem?.PlaybackCountdownProgress ?? 0d;
|
||||||
|
|
||||||
public double CurrentPreviewWidth => ResolvePlaybackPreviewMetrics(CurrentPlaybackItem).Width;
|
public double CurrentPreviewWidth => ResolvePlaybackPreviewMetrics(CurrentPlaybackItem).Width;
|
||||||
|
|
||||||
public double CurrentPreviewHeight => ResolvePlaybackPreviewMetrics(CurrentPlaybackItem).Height;
|
public double CurrentPreviewHeight => ResolvePlaybackPreviewMetrics(CurrentPlaybackItem).Height;
|
||||||
@@ -892,6 +901,10 @@ public sealed class ChannelScheduleViewModel : ObservableObject
|
|||||||
nameof(NextPreviewSource),
|
nameof(NextPreviewSource),
|
||||||
nameof(CurrentPreviewStatusLabel),
|
nameof(CurrentPreviewStatusLabel),
|
||||||
nameof(NextPreviewStatusLabel),
|
nameof(NextPreviewStatusLabel),
|
||||||
|
nameof(PlaybackCountdownVisibility),
|
||||||
|
nameof(PlaybackCountdownText),
|
||||||
|
nameof(PlaybackCountdownDetail),
|
||||||
|
nameof(PlaybackCountdownProgress),
|
||||||
nameof(CurrentPreviewWidth),
|
nameof(CurrentPreviewWidth),
|
||||||
nameof(CurrentPreviewHeight),
|
nameof(CurrentPreviewHeight),
|
||||||
nameof(NextPreviewWidth),
|
nameof(NextPreviewWidth),
|
||||||
@@ -1155,6 +1168,10 @@ public sealed class ChannelScheduleViewModel : ObservableObject
|
|||||||
or nameof(ChannelScheduleItem.HasInternalNextPreview)
|
or nameof(ChannelScheduleItem.HasInternalNextPreview)
|
||||||
or nameof(ChannelScheduleItem.LastError)
|
or nameof(ChannelScheduleItem.LastError)
|
||||||
or nameof(ChannelScheduleItem.LastIssueAt)
|
or nameof(ChannelScheduleItem.LastIssueAt)
|
||||||
|
or nameof(ChannelScheduleItem.PlaybackCountdownVisibility)
|
||||||
|
or nameof(ChannelScheduleItem.PlaybackCountdownText)
|
||||||
|
or nameof(ChannelScheduleItem.PlaybackCountdownDetail)
|
||||||
|
or nameof(ChannelScheduleItem.PlaybackCountdownProgress)
|
||||||
or nameof(ChannelScheduleItem.ThumbnailSource))
|
or nameof(ChannelScheduleItem.ThumbnailSource))
|
||||||
{
|
{
|
||||||
if (e.PropertyName is nameof(ChannelScheduleItem.State)
|
if (e.PropertyName is nameof(ChannelScheduleItem.State)
|
||||||
@@ -1182,6 +1199,10 @@ public sealed class ChannelScheduleViewModel : ObservableObject
|
|||||||
nameof(QueuedItemCount),
|
nameof(QueuedItemCount),
|
||||||
nameof(QueueFootnote),
|
nameof(QueueFootnote),
|
||||||
nameof(QueueSummary),
|
nameof(QueueSummary),
|
||||||
|
nameof(PlaybackCountdownVisibility),
|
||||||
|
nameof(PlaybackCountdownText),
|
||||||
|
nameof(PlaybackCountdownDetail),
|
||||||
|
nameof(PlaybackCountdownProgress),
|
||||||
nameof(ScheduleDataIssueVisibility),
|
nameof(ScheduleDataIssueVisibility),
|
||||||
nameof(ScheduleDataIssueBackgroundBrush),
|
nameof(ScheduleDataIssueBackgroundBrush),
|
||||||
nameof(ScheduleDataIssueBorderBrush),
|
nameof(ScheduleDataIssueBorderBrush),
|
||||||
@@ -1198,6 +1219,10 @@ public sealed class ChannelScheduleViewModel : ObservableObject
|
|||||||
nameof(NextPreviewSource),
|
nameof(NextPreviewSource),
|
||||||
nameof(CurrentPreviewStatusLabel),
|
nameof(CurrentPreviewStatusLabel),
|
||||||
nameof(NextPreviewStatusLabel),
|
nameof(NextPreviewStatusLabel),
|
||||||
|
nameof(PlaybackCountdownVisibility),
|
||||||
|
nameof(PlaybackCountdownText),
|
||||||
|
nameof(PlaybackCountdownDetail),
|
||||||
|
nameof(PlaybackCountdownProgress),
|
||||||
nameof(CurrentPreviewWidth),
|
nameof(CurrentPreviewWidth),
|
||||||
nameof(CurrentPreviewHeight),
|
nameof(CurrentPreviewHeight),
|
||||||
nameof(NextPreviewWidth),
|
nameof(NextPreviewWidth),
|
||||||
|
|||||||
Reference in New Issue
Block a user