Files @ 5e28ba3945f7
Branch filter:

Location: ATITD-Tools/Desert-Paint-Codex/ViewModels/SimulatorViewModel.cs - annotation

Jason Maltzen
Recipe count is now a ulong instead of an int so it can show values > 2.47 billion. Also, don't allow clearing the recipe list while the recipe generator is running.
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using Avalonia;
using Avalonia.Input.Platform;
using DesertPaintCodex.Models;
using DesertPaintCodex.Services;
using DynamicData;
using DynamicData.Binding;
using ReactiveUI;

namespace DesertPaintCodex.ViewModels
{
    public class SimulatorViewModel : ViewModelBase
    {
        private PaintColor? _paintColor;
        public PaintColor? PaintColor
        {
            get => _paintColor;
            set => this.RaiseAndSetIfChanged(ref _paintColor, value);
        }

        private bool _hasMissingReactions;
        public bool HasMissingReactions
        {
            get => _hasMissingReactions;
            set => this.RaiseAndSetIfChanged(ref _hasMissingReactions, value);
        }

        private bool _isGoodRecipe;

        public bool IsGoodRecipe
        {
            get => _isGoodRecipe;
            set => this.RaiseAndSetIfChanged(ref _isGoodRecipe, value);
        }
        
        public ObservableCollection<Reagent> Reagents { get; } = new();
        public ObservableCollection<Reagent> ActiveReagents { get; } = new();
        public ObservableCollection<RecipeItem> RecipeItems { get; } = new();

        
        private readonly PaintRecipe _currentRecipe = new();

        public SimulatorViewModel()
        {
            List<string> reagentNames = ReagentService.Names;
            for (int i = 0; i < reagentNames.Count; i++)
            {
                Reagents.Add(ReagentService.GetReagent(reagentNames[i]));
            }

            ActiveReagents.CollectionChanged += OnActiveReagentsChanged;

            RecipeItems
                .ToObservableChangeSet()
                .AutoRefresh(item => item.Quantity)
                .Subscribe(_ => Refresh());
        }

        public async void CopyToClipboard()
        {
            IClipboard clipboard = Application.Current.Clipboard;
            await clipboard.SetTextAsync(_currentRecipe.ToString());
        }

        public void MoveItemUp(RecipeItem item)
        {
            int pos = RecipeItems.IndexOf(item);
            if (pos <= 0) return;

            RecipeItems.RemoveAt(pos);
            RecipeItems.Insert(pos - 1, item);

            Refresh();
        }

        public void MoveItemDown(RecipeItem item)
        {
            int pos = RecipeItems.IndexOf(item);
            if ((pos < 0) || (pos >= RecipeItems.Count - 1)) return;

            RecipeItems.RemoveAt(pos);
            RecipeItems.Insert(pos + 1, item);

            Refresh();
        }
        
        private void UpdateRecipe()
        {
            _currentRecipe.Clear();
            foreach (RecipeItem entry in RecipeItems)
            {
                if (!entry.Unused)
                {
                    _currentRecipe.AddReagent(entry.Reagent.Name, entry.Quantity);
                }
            }

            PaintColor = null; // TODO: Find a better way to kick the paint swatch when reassigning color from the same ref.
            PaintColor          = _currentRecipe.ReactedColor;
            HasMissingReactions = _currentRecipe.HasMissingReactions();
            IsGoodRecipe        = !HasMissingReactions && _currentRecipe.IsValidForConcentration(10);
        }

        private void OnActiveReagentsChanged(object? sender, NotifyCollectionChangedEventArgs e)
        {
            HashSet<Reagent> unmatchedReagents = new(ActiveReagents);
            
            for (int i = RecipeItems.Count - 1; i >= 0; i--)
            {
                bool found = false;
                foreach (Reagent reagent in ActiveReagents)
                {
                    if (reagent == RecipeItems[i].Reagent)
                    {
                        unmatchedReagents.Remove(reagent);
                        found = true;
                        break;
                    }
                }

                if (!found) RecipeItems.RemoveAt(i);
            }

            foreach (Reagent reagent in unmatchedReagents)
            {
                RecipeItems.Add(new RecipeItem(reagent, 1));
            }

            Refresh();
        }

        private void Refresh()
        {
            UpdateFlags();
            UpdateRecipe();
        }

        private void UpdateFlags()
        {
            int activeIngredients = 0;
            for (int i = 0; i < RecipeItems.Count; i++)
            {
                RecipeItem item = RecipeItems[i];
                item.First = i == 0;
                item.Last = i == RecipeItems.Count - 1;
                if (item.Quantity > 0)
                {
                    activeIngredients++;
                }
                item.Unused = ((activeIngredients > 5) && item.Reagent.IsCatalyst) || (item.Quantity == 0);
            }
        }
    }
}