146 lines
4.3 KiB
C#
146 lines
4.3 KiB
C#
using System.Collections.ObjectModel;
|
|
using System.Threading.Tasks;
|
|
using CommunityToolkit.Mvvm.ComponentModel;
|
|
using CommunityToolkit.Mvvm.Input;
|
|
using AdvancedCalculator.Models;
|
|
using AdvancedCalculator.Services;
|
|
using CSMic;
|
|
using System;
|
|
using System.Reflection;
|
|
|
|
namespace AdvancedCalculator.ViewModels;
|
|
|
|
public partial class MainViewModel : ViewModelBase
|
|
{
|
|
private readonly ICalculatorService _calculatorService;
|
|
public event EventHandler<string>? CopyRequested;
|
|
|
|
public MainViewModel()
|
|
: this(new CalculatorService())
|
|
{
|
|
}
|
|
|
|
public MainViewModel(ICalculatorService calculatorService)
|
|
{
|
|
_calculatorService = calculatorService;
|
|
History = new ObservableCollection<HistoryItem>();
|
|
Variables = new ObservableCollection<VariableItem>();
|
|
}
|
|
|
|
[ObservableProperty]
|
|
private string _inputText = string.Empty;
|
|
|
|
[ObservableProperty]
|
|
private bool _isFunctionsPanelOpen;
|
|
|
|
[ObservableProperty]
|
|
private int _selectedHistoryIndex = -1;
|
|
|
|
// Caret position in the input TextBox
|
|
[ObservableProperty]
|
|
private int _caretIndex;
|
|
|
|
public ObservableCollection<HistoryItem> History { get; }
|
|
public ObservableCollection<VariableItem> Variables { get; }
|
|
|
|
// App version string, sourced from AssemblyInformationalVersion
|
|
public string AppVersion { get; } =
|
|
typeof(MainViewModel).Assembly
|
|
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?
|
|
.InformationalVersion ?? "0.0.0";
|
|
|
|
[RelayCommand]
|
|
private void ToggleFunctions()
|
|
{
|
|
IsFunctionsPanelOpen = !IsFunctionsPanelOpen;
|
|
}
|
|
|
|
// Insert helpers for touch: appends tokens to the input box
|
|
[RelayCommand]
|
|
private void InsertVariable(VariableItem variableItem)
|
|
{
|
|
if (variableItem == null) return;
|
|
if (string.IsNullOrWhiteSpace(variableItem.VariableName))
|
|
return;
|
|
InsertToken(variableItem.VariableName);
|
|
}
|
|
|
|
[RelayCommand]
|
|
private void InsertFunction(FunctionDefinitionItem functionDefintionItem)
|
|
{
|
|
if (functionDefintionItem == null) return;
|
|
if (string.IsNullOrWhiteSpace(functionDefintionItem.FunctionName))
|
|
return;
|
|
InsertToken(functionDefintionItem.FunctionName + "()");
|
|
// Place caret inside the parentheses
|
|
if (!string.IsNullOrEmpty(InputText))
|
|
{
|
|
CaretIndex = Math.Max(0, InputText.Length - 1);
|
|
}
|
|
// Close the functions flyout after insertion for smoother UX
|
|
IsFunctionsPanelOpen = false;
|
|
}
|
|
|
|
private void InsertToken(string token)
|
|
{
|
|
if (string.IsNullOrEmpty(InputText))
|
|
{
|
|
InputText = token;
|
|
return;
|
|
}
|
|
|
|
if (!char.IsWhiteSpace(InputText[^1]))
|
|
InputText += " ";
|
|
|
|
InputText += token;
|
|
}
|
|
|
|
[RelayCommand(AllowConcurrentExecutions = false)]
|
|
private async Task Submit()
|
|
{
|
|
var text = InputText?.Trim();
|
|
if (string.IsNullOrEmpty(text))
|
|
return;
|
|
|
|
var result = await _calculatorService.InterpretAsync(text);
|
|
|
|
History.Add(new HistoryItem { Input = text, Output = result.Output });
|
|
|
|
Variables.Clear();
|
|
foreach (var v in result.Variables)
|
|
{
|
|
Variables.Add(v);
|
|
}
|
|
|
|
InputText = string.Empty;
|
|
SelectedHistoryIndex = History.Count - 1;
|
|
}
|
|
|
|
// Copy helpers (MVVM-pure): build text in VM, View handles clipboard via CopyRequested
|
|
[RelayCommand]
|
|
private void CopyHistoryInput(HistoryItem? item)
|
|
{
|
|
if (item is null || string.IsNullOrWhiteSpace(item.Input)) return;
|
|
CopyRequested?.Invoke(this, item.Input);
|
|
}
|
|
|
|
[RelayCommand]
|
|
private void CopyHistoryOutput(HistoryItem? item)
|
|
{
|
|
if (item is null || string.IsNullOrWhiteSpace(item.Output)) return;
|
|
CopyRequested?.Invoke(this, item.Output);
|
|
}
|
|
|
|
[RelayCommand]
|
|
private void CopyHistoryBoth(HistoryItem? item)
|
|
{
|
|
if (item is null) return;
|
|
var input = item.Input?.Trim();
|
|
var output = item.Output?.Trim();
|
|
if (string.IsNullOrEmpty(input) && string.IsNullOrEmpty(output)) return;
|
|
if (string.IsNullOrEmpty(input)) { CopyRequested?.Invoke(this, output!); return; }
|
|
if (string.IsNullOrEmpty(output)) { CopyRequested?.Invoke(this, input!); return; }
|
|
|
|
CopyRequested?.Invoke(this, $"{input} = {output}");
|
|
}
|
|
}
|