using Spectre.Console;
using SPT_AKI_Installer.Aki.Core.Interfaces;
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace SPT_AKI_Installer.Aki.Core.Model
{
public abstract class LiveTableTask : ILiveTaskTableEntry, IProgressableTask, IDisposable
{
///
/// The name that will be displayed in th first column of the table
///
public string TaskName { get; set; }
///
/// Wheather the task reports progress or not
///
public bool IsIndeterminate;
///
/// The progress (percent completed) of the task
///
public int Progress { get; set; }
///
/// The row index in the table of the task
///
public int RowIndex { get; set; }
private bool _continueRendering = false;
private int _indeterminateState = 0;
private string _currentStatus = "running";
private Table _table { get; set; }
private LiveDisplayContext _context { get; set; }
public LiveTableTask(string name, bool isIndeterminate = true)
{
TaskName = name;
IsIndeterminate = isIndeterminate;
}
private string GetIndetermminateStatus()
{
string status = $"[blue]{_currentStatus.EscapeMarkup()} ";
if (_indeterminateState > 3) _indeterminateState = 0;
status += new string('.', _indeterminateState);
status += "[/]";
_indeterminateState++;
return status;
}
///
/// Start indeterminate progress spinner
///
/// this doesn't need to be called if you set isIndeterminate in the constructor. You need to set IsIndeterminate to false to stop this background task
public void StartDrawingIndeterminateProgress()
{
_continueRendering = true;
new Task(new Action(() => { RenderIndeterminateProgress(ref _continueRendering); })).Start();
}
public void StartDrawingProgress()
{
_continueRendering = true;
new Task(new Action(() => { RenderProgress(ref _continueRendering); })).Start();
}
private void ReRenderEntry(string message)
{
_table.RemoveRow(RowIndex);
_table.InsertRow(RowIndex, TaskName, message);
_context.Refresh();
}
private void RenderIndeterminateProgress(ref bool continueRendering)
{
while (continueRendering)
{
ReRenderEntry(GetIndetermminateStatus());
Thread.Sleep(300);
}
}
private void RenderProgress(ref bool continueRendering)
{
while (continueRendering)
{
string progressBar = new string(' ', 10);
int progressFill = (int)Math.Floor((double)Progress / 10);
progressBar = progressBar.Remove(0, progressFill).Insert(0, new string('=', progressFill));
progressBar = $"[blue][[{progressBar}]][/] {Progress}% {_currentStatus}";
ReRenderEntry(progressBar);
Thread.Sleep(300);
}
}
///
/// Set the context and table for this task
///
///
///
/// This is called by when it is ran. No need to call it yourself
public void SetContext(LiveDisplayContext context, Table table)
{
_context = context;
_table = table;
}
///
/// Set the status text for the task
///
/// The message to show
/// Stop rendering progress updates (progress and indeterminate progress tasks)
/// If you are running an indeterminate task, set render to false. It will render at the next indeterminate update interval
public void SetStatus(string message, bool stopRendering = true)
{
_currentStatus = message;
if (stopRendering)
{
_continueRendering = false;
ReRenderEntry(message);
}
}
///
/// Run the task async
///
/// Returns the result of the task
public abstract Task RunAsync();
public void Dispose()
{
IsIndeterminate = false;
}
}
}