work on inventory
This commit is contained in:
parent
50d32abd49
commit
32781b1462
11 changed files with 240 additions and 146 deletions
|
|
@ -181,14 +181,17 @@ public class BotOrchestrator : IAsyncDisposable
|
||||||
|
|
||||||
await ocrWarmup;
|
await ocrWarmup;
|
||||||
|
|
||||||
Emit("info", "Checking inventory for leftover items...");
|
|
||||||
await Inventory.ClearToStash();
|
|
||||||
Emit("info", "Inventory cleared");
|
|
||||||
|
|
||||||
// Wire executor events
|
// Wire executor events
|
||||||
TradeExecutor.StateChanged += _ => UpdateExecutorState();
|
TradeExecutor.StateChanged += _ => UpdateExecutorState();
|
||||||
TradeQueue.TradeCompleted += () => { _tradesCompleted++; StatusUpdated?.Invoke(); };
|
TradeQueue.TradeCompleted += () => { _tradesCompleted++; StatusUpdated?.Invoke(); };
|
||||||
TradeQueue.TradeFailed += () => { _tradesFailed++; StatusUpdated?.Invoke(); };
|
TradeQueue.TradeFailed += () => { _tradesFailed++; StatusUpdated?.Invoke(); };
|
||||||
|
Inventory.Updated += () => StatusUpdated?.Invoke();
|
||||||
|
|
||||||
|
_started = true;
|
||||||
|
|
||||||
|
Emit("info", "Checking inventory for leftover items...");
|
||||||
|
await Inventory.ClearToStash();
|
||||||
|
Emit("info", "Inventory cleared");
|
||||||
|
|
||||||
// Load links
|
// Load links
|
||||||
var allUrls = new HashSet<string>(cliUrls);
|
var allUrls = new HashSet<string>(cliUrls);
|
||||||
|
|
@ -207,7 +210,6 @@ public class BotOrchestrator : IAsyncDisposable
|
||||||
// Wire trade monitor events
|
// Wire trade monitor events
|
||||||
TradeMonitor.NewListings += OnNewListings;
|
TradeMonitor.NewListings += OnNewListings;
|
||||||
|
|
||||||
_started = true;
|
|
||||||
Emit("info", $"Loaded {allUrls.Count} trade link(s)");
|
Emit("info", $"Loaded {allUrls.Count} trade link(s)");
|
||||||
Log.Information("Bot started");
|
Log.Information("Bot started");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ public class SavedSettings
|
||||||
public double? WindowY { get; set; }
|
public double? WindowY { get; set; }
|
||||||
public double? WindowWidth { get; set; }
|
public double? WindowWidth { get; set; }
|
||||||
public double? WindowHeight { get; set; }
|
public double? WindowHeight { get; set; }
|
||||||
|
public bool Headless { get; set; } = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ConfigStore
|
public class ConfigStore
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,9 @@ namespace Poe2Trade.Inventory;
|
||||||
|
|
||||||
public interface IInventoryManager
|
public interface IInventoryManager
|
||||||
{
|
{
|
||||||
|
event Action? Updated;
|
||||||
InventoryTracker Tracker { get; }
|
InventoryTracker Tracker { get; }
|
||||||
|
byte[]? LastScreenshot { get; }
|
||||||
bool IsAtOwnHideout { get; }
|
bool IsAtOwnHideout { get; }
|
||||||
string SellerAccount { get; }
|
string SellerAccount { get; }
|
||||||
void SetLocation(bool atHome, string? seller = null);
|
void SetLocation(bool atHome, string? seller = null);
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ public class InventoryManager : IInventoryManager
|
||||||
{
|
{
|
||||||
private static readonly string SalvageTemplate = Path.Combine("assets", "salvage.png");
|
private static readonly string SalvageTemplate = Path.Combine("assets", "salvage.png");
|
||||||
|
|
||||||
|
public event Action? Updated;
|
||||||
public InventoryTracker Tracker { get; } = new();
|
public InventoryTracker Tracker { get; } = new();
|
||||||
|
|
||||||
private bool _atOwnHideout = true;
|
private bool _atOwnHideout = true;
|
||||||
|
|
@ -19,6 +20,7 @@ public class InventoryManager : IInventoryManager
|
||||||
private readonly IClientLogWatcher _logWatcher;
|
private readonly IClientLogWatcher _logWatcher;
|
||||||
private readonly SavedSettings _config;
|
private readonly SavedSettings _config;
|
||||||
|
|
||||||
|
public byte[]? LastScreenshot { get; private set; }
|
||||||
public bool IsAtOwnHideout => _atOwnHideout;
|
public bool IsAtOwnHideout => _atOwnHideout;
|
||||||
public string SellerAccount => _sellerAccount;
|
public string SellerAccount => _sellerAccount;
|
||||||
|
|
||||||
|
|
@ -44,6 +46,7 @@ public class InventoryManager : IInventoryManager
|
||||||
await _game.OpenInventory();
|
await _game.OpenInventory();
|
||||||
|
|
||||||
var result = await _screen.Grid.Scan("inventory");
|
var result = await _screen.Grid.Scan("inventory");
|
||||||
|
LastScreenshot = await _screen.CaptureRegion(GridLayouts.Inventory.Region);
|
||||||
|
|
||||||
var cells = new bool[5, 12];
|
var cells = new bool[5, 12];
|
||||||
foreach (var cell in result.Occupied)
|
foreach (var cell in result.Occupied)
|
||||||
|
|
@ -52,6 +55,7 @@ public class InventoryManager : IInventoryManager
|
||||||
cells[cell.Row, cell.Col] = true;
|
cells[cell.Row, cell.Col] = true;
|
||||||
}
|
}
|
||||||
Tracker.InitFromScan(cells, result.Items, defaultAction);
|
Tracker.InitFromScan(cells, result.Items, defaultAction);
|
||||||
|
Updated?.Invoke();
|
||||||
|
|
||||||
await _game.PressEscape();
|
await _game.PressEscape();
|
||||||
await Helpers.Sleep(Delays.PostFocus);
|
await Helpers.Sleep(Delays.PostFocus);
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ public class TradeMonitor : ITradeMonitor
|
||||||
_config.BrowserUserDataDir,
|
_config.BrowserUserDataDir,
|
||||||
new BrowserTypeLaunchPersistentContextOptions
|
new BrowserTypeLaunchPersistentContextOptions
|
||||||
{
|
{
|
||||||
Headless = false,
|
Headless = _config.Headless,
|
||||||
ViewportSize = null,
|
ViewportSize = null,
|
||||||
Args = [
|
Args = [
|
||||||
"--disable-blink-features=AutomationControlled",
|
"--disable-blink-features=AutomationControlled",
|
||||||
|
|
|
||||||
|
|
@ -13,5 +13,6 @@
|
||||||
<conv:StatusDotBrushConverter x:Key="StatusDotBrush" />
|
<conv:StatusDotBrushConverter x:Key="StatusDotBrush" />
|
||||||
<conv:ActiveOpacityConverter x:Key="ActiveOpacity" />
|
<conv:ActiveOpacityConverter x:Key="ActiveOpacity" />
|
||||||
<conv:CellBorderConverter x:Key="CellBorderConverter" />
|
<conv:CellBorderConverter x:Key="CellBorderConverter" />
|
||||||
|
<conv:BoolToOverlayBrushConverter x:Key="OccupiedOverlayBrush" />
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
</Application>
|
</Application>
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ public class LinkModeToColorConverter : IValueConverter
|
||||||
{
|
{
|
||||||
LinkMode.Live => new SolidColorBrush(Color.Parse("#1f6feb")),
|
LinkMode.Live => new SolidColorBrush(Color.Parse("#1f6feb")),
|
||||||
LinkMode.Scrap => new SolidColorBrush(Color.Parse("#9e6a03")),
|
LinkMode.Scrap => new SolidColorBrush(Color.Parse("#9e6a03")),
|
||||||
|
|
||||||
_ => new SolidColorBrush(Color.Parse("#30363d")),
|
_ => new SolidColorBrush(Color.Parse("#30363d")),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -79,6 +80,20 @@ public class ActiveOpacityConverter : IValueConverter
|
||||||
=> throw new NotSupportedException();
|
=> throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class BoolToOverlayBrushConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
var occupied = value is true;
|
||||||
|
return occupied
|
||||||
|
? new SolidColorBrush(Color.FromArgb(64, 56, 168, 50))
|
||||||
|
: Brushes.Transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
|
=> throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
public class CellBorderConverter : IValueConverter
|
public class CellBorderConverter : IValueConverter
|
||||||
{
|
{
|
||||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.IO;
|
||||||
|
using Avalonia.Media.Imaging;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Poe2Trade.Bot;
|
using Poe2Trade.Bot;
|
||||||
|
|
@ -39,6 +41,8 @@ public partial class MainWindowViewModel : ObservableObject
|
||||||
[NotifyCanExecuteChangedFor(nameof(PauseCommand))]
|
[NotifyCanExecuteChangedFor(nameof(PauseCommand))]
|
||||||
private bool _isStarted;
|
private bool _isStarted;
|
||||||
|
|
||||||
|
[ObservableProperty] private Bitmap? _inventoryImage;
|
||||||
|
|
||||||
[ObservableProperty] private string _newUrl = "";
|
[ObservableProperty] private string _newUrl = "";
|
||||||
[ObservableProperty] private string _newLinkName = "";
|
[ObservableProperty] private string _newLinkName = "";
|
||||||
[ObservableProperty] private LinkMode _newLinkMode = LinkMode.Live;
|
[ObservableProperty] private LinkMode _newLinkMode = LinkMode.Live;
|
||||||
|
|
@ -178,6 +182,20 @@ public partial class MainWindowViewModel : ObservableObject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var bytes = _bot.Inventory.LastScreenshot;
|
||||||
|
if (bytes != null)
|
||||||
|
{
|
||||||
|
var old = InventoryImage;
|
||||||
|
InventoryImage = new Bitmap(new MemoryStream(bytes));
|
||||||
|
old?.Dispose();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var old = InventoryImage;
|
||||||
|
InventoryImage = null;
|
||||||
|
old?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
OnPropertyChanged(nameof(InventoryFreeCells));
|
OnPropertyChanged(nameof(InventoryFreeCells));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ public partial class SettingsViewModel : ObservableObject
|
||||||
[ObservableProperty] private decimal? _stashScanTimeoutMs = 10000;
|
[ObservableProperty] private decimal? _stashScanTimeoutMs = 10000;
|
||||||
[ObservableProperty] private decimal? _waitForMoreItemsMs = 20000;
|
[ObservableProperty] private decimal? _waitForMoreItemsMs = 20000;
|
||||||
[ObservableProperty] private decimal? _betweenTradesDelayMs = 5000;
|
[ObservableProperty] private decimal? _betweenTradesDelayMs = 5000;
|
||||||
|
[ObservableProperty] private bool _headless = true;
|
||||||
[ObservableProperty] private bool _isSaved;
|
[ObservableProperty] private bool _isSaved;
|
||||||
|
|
||||||
public SettingsViewModel(BotOrchestrator bot)
|
public SettingsViewModel(BotOrchestrator bot)
|
||||||
|
|
@ -31,6 +32,7 @@ public partial class SettingsViewModel : ObservableObject
|
||||||
StashScanTimeoutMs = s.StashScanTimeoutMs;
|
StashScanTimeoutMs = s.StashScanTimeoutMs;
|
||||||
WaitForMoreItemsMs = s.WaitForMoreItemsMs;
|
WaitForMoreItemsMs = s.WaitForMoreItemsMs;
|
||||||
BetweenTradesDelayMs = s.BetweenTradesDelayMs;
|
BetweenTradesDelayMs = s.BetweenTradesDelayMs;
|
||||||
|
Headless = s.Headless;
|
||||||
}
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
|
|
@ -44,6 +46,7 @@ public partial class SettingsViewModel : ObservableObject
|
||||||
s.StashScanTimeoutMs = (int)(StashScanTimeoutMs ?? 10000);
|
s.StashScanTimeoutMs = (int)(StashScanTimeoutMs ?? 10000);
|
||||||
s.WaitForMoreItemsMs = (int)(WaitForMoreItemsMs ?? 20000);
|
s.WaitForMoreItemsMs = (int)(WaitForMoreItemsMs ?? 20000);
|
||||||
s.BetweenTradesDelayMs = (int)(BetweenTradesDelayMs ?? 5000);
|
s.BetweenTradesDelayMs = (int)(BetweenTradesDelayMs ?? 5000);
|
||||||
|
s.Headless = Headless;
|
||||||
});
|
});
|
||||||
|
|
||||||
IsSaved = true;
|
IsSaved = true;
|
||||||
|
|
@ -55,4 +58,5 @@ public partial class SettingsViewModel : ObservableObject
|
||||||
partial void OnStashScanTimeoutMsChanged(decimal? value) => IsSaved = false;
|
partial void OnStashScanTimeoutMsChanged(decimal? value) => IsSaved = false;
|
||||||
partial void OnWaitForMoreItemsMsChanged(decimal? value) => IsSaved = false;
|
partial void OnWaitForMoreItemsMsChanged(decimal? value) => IsSaved = false;
|
||||||
partial void OnBetweenTradesDelayMsChanged(decimal? value) => IsSaved = false;
|
partial void OnBetweenTradesDelayMsChanged(decimal? value) => IsSaved = false;
|
||||||
|
partial void OnHeadlessChanged(bool value) => IsSaved = false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,14 @@
|
||||||
xmlns:vm="using:Poe2Trade.Ui.ViewModels"
|
xmlns:vm="using:Poe2Trade.Ui.ViewModels"
|
||||||
x:Class="Poe2Trade.Ui.Views.MainWindow"
|
x:Class="Poe2Trade.Ui.Views.MainWindow"
|
||||||
x:DataType="vm:MainWindowViewModel"
|
x:DataType="vm:MainWindowViewModel"
|
||||||
Title="POE2 Trade Bot"
|
Title="Automata"
|
||||||
Width="960" Height="720"
|
Width="960" Height="640"
|
||||||
Background="#0d1117">
|
Background="#0d1117">
|
||||||
|
|
||||||
<DockPanel Margin="12">
|
<DockPanel Margin="8">
|
||||||
|
|
||||||
<!-- STATUS HEADER -->
|
<!-- STATUS HEADER -->
|
||||||
<Border DockPanel.Dock="Top" Padding="12" Margin="0,0,0,8"
|
<Border DockPanel.Dock="Top" Padding="8" Margin="0,0,0,6"
|
||||||
Background="#161b22" BorderBrush="#30363d"
|
Background="#161b22" BorderBrush="#30363d"
|
||||||
BorderThickness="1" CornerRadius="8">
|
BorderThickness="1" CornerRadius="8">
|
||||||
<Grid ColumnDefinitions="Auto,*,Auto">
|
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||||
|
|
@ -24,30 +24,30 @@
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<!-- Stats cards -->
|
<!-- Stats cards -->
|
||||||
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="16"
|
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="10"
|
||||||
HorizontalAlignment="Center">
|
HorizontalAlignment="Center">
|
||||||
<Border Background="#21262d" CornerRadius="6" Padding="16,8">
|
<Border Background="#21262d" CornerRadius="6" Padding="10,4">
|
||||||
<StackPanel HorizontalAlignment="Center">
|
<StackPanel HorizontalAlignment="Center">
|
||||||
<TextBlock Text="{Binding ActiveLinksCount}"
|
<TextBlock Text="{Binding ActiveLinksCount}"
|
||||||
FontSize="20" FontWeight="Bold" Foreground="#58a6ff"
|
FontSize="16" FontWeight="Bold" Foreground="#58a6ff"
|
||||||
HorizontalAlignment="Center" />
|
HorizontalAlignment="Center" />
|
||||||
<TextBlock Text="ACTIVE LINKS" FontSize="10" Foreground="#8b949e"
|
<TextBlock Text="ACTIVE LINKS" FontSize="10" Foreground="#8b949e"
|
||||||
HorizontalAlignment="Center" />
|
HorizontalAlignment="Center" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
<Border Background="#21262d" CornerRadius="6" Padding="16,8">
|
<Border Background="#21262d" CornerRadius="6" Padding="10,4">
|
||||||
<StackPanel HorizontalAlignment="Center">
|
<StackPanel HorizontalAlignment="Center">
|
||||||
<TextBlock Text="{Binding TradesCompleted}"
|
<TextBlock Text="{Binding TradesCompleted}"
|
||||||
FontSize="20" FontWeight="Bold" Foreground="#3fb950"
|
FontSize="16" FontWeight="Bold" Foreground="#3fb950"
|
||||||
HorizontalAlignment="Center" />
|
HorizontalAlignment="Center" />
|
||||||
<TextBlock Text="TRADES DONE" FontSize="10" Foreground="#8b949e"
|
<TextBlock Text="TRADES DONE" FontSize="10" Foreground="#8b949e"
|
||||||
HorizontalAlignment="Center" />
|
HorizontalAlignment="Center" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
<Border Background="#21262d" CornerRadius="6" Padding="16,8">
|
<Border Background="#21262d" CornerRadius="6" Padding="10,4">
|
||||||
<StackPanel HorizontalAlignment="Center">
|
<StackPanel HorizontalAlignment="Center">
|
||||||
<TextBlock Text="{Binding TradesFailed}"
|
<TextBlock Text="{Binding TradesFailed}"
|
||||||
FontSize="20" FontWeight="Bold" Foreground="#f85149"
|
FontSize="16" FontWeight="Bold" Foreground="#f85149"
|
||||||
HorizontalAlignment="Center" />
|
HorizontalAlignment="Center" />
|
||||||
<TextBlock Text="FAILED" FontSize="10" Foreground="#8b949e"
|
<TextBlock Text="FAILED" FontSize="10" Foreground="#8b949e"
|
||||||
HorizontalAlignment="Center" />
|
HorizontalAlignment="Center" />
|
||||||
|
|
@ -66,134 +66,127 @@
|
||||||
<!-- TABBED CONTENT -->
|
<!-- TABBED CONTENT -->
|
||||||
<TabControl>
|
<TabControl>
|
||||||
|
|
||||||
<!-- ========== MAIN TAB ========== -->
|
<!-- ========== STATE TAB ========== -->
|
||||||
<TabItem Header="Main">
|
<TabItem Header="State">
|
||||||
<Grid RowDefinitions="Auto,*" Margin="0,8,0,0">
|
<Grid RowDefinitions="Auto,*" Margin="0,6,0,0">
|
||||||
|
|
||||||
<!-- Inventory Grid (12x5) -->
|
<!-- Inventory Grid (12x5) -->
|
||||||
<Border Grid.Row="0" Background="#161b22" BorderBrush="#30363d"
|
<Border Grid.Row="0" Background="#161b22" BorderBrush="#30363d"
|
||||||
BorderThickness="1" CornerRadius="8" Padding="10" Margin="0,0,0,8">
|
BorderThickness="1" CornerRadius="8" Padding="8" Margin="0,0,0,6">
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="0,0,0,6">
|
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="0,0,0,4">
|
||||||
<TextBlock Text="INVENTORY" FontSize="11" FontWeight="SemiBold"
|
<TextBlock Text="INVENTORY" FontSize="11" FontWeight="SemiBold"
|
||||||
Foreground="#8b949e" />
|
Foreground="#8b949e" />
|
||||||
<TextBlock Text="{Binding InventoryFreeCells, StringFormat='{}{0}/60 free'}"
|
<TextBlock Text="{Binding InventoryFreeCells, StringFormat='{}{0}/60 free'}"
|
||||||
FontSize="11" Foreground="#8b949e" Margin="12,0,0,0" />
|
FontSize="11" Foreground="#8b949e" Margin="12,0,0,0" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<ItemsControl ItemsSource="{Binding InventoryCells}">
|
<Grid MaxHeight="170">
|
||||||
<ItemsControl.ItemsPanel>
|
<Image Source="{Binding InventoryImage}" Stretch="Uniform" />
|
||||||
<ItemsPanelTemplate>
|
<ItemsControl ItemsSource="{Binding InventoryCells}">
|
||||||
<UniformGrid Columns="12" Rows="5" />
|
<ItemsControl.ItemsPanel>
|
||||||
</ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
</ItemsControl.ItemsPanel>
|
<UniformGrid Columns="12" Rows="5" />
|
||||||
<ItemsControl.ItemTemplate>
|
</ItemsPanelTemplate>
|
||||||
<DataTemplate x:DataType="vm:CellState">
|
</ItemsControl.ItemsPanel>
|
||||||
<Border Margin="1" CornerRadius="2" Height="22"
|
<ItemsControl.ItemTemplate>
|
||||||
Background="{Binding IsOccupied, Converter={StaticResource OccupiedBrush}}"
|
<DataTemplate x:DataType="vm:CellState">
|
||||||
BorderBrush="#3fb950" />
|
<Border Margin="1" CornerRadius="2"
|
||||||
</DataTemplate>
|
Background="{Binding IsOccupied, Converter={StaticResource OccupiedOverlayBrush}}"
|
||||||
</ItemsControl.ItemTemplate>
|
BorderBrush="#3fb950"
|
||||||
</ItemsControl>
|
BorderThickness="{Binding Converter={StaticResource CellBorderConverter}}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</Grid>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<!-- Links + Logs split -->
|
<!-- Logs -->
|
||||||
<Grid Grid.Row="1" ColumnDefinitions="350,*">
|
<Border Grid.Row="1" Background="#0d1117" BorderBrush="#30363d"
|
||||||
|
BorderThickness="1" CornerRadius="8" Padding="8">
|
||||||
<!-- Left: Trade Links -->
|
<DockPanel>
|
||||||
<Border Grid.Column="0" Background="#161b22" BorderBrush="#30363d"
|
<TextBlock DockPanel.Dock="Top" Text="ACTIVITY LOG"
|
||||||
BorderThickness="1" CornerRadius="8" Padding="10" Margin="0,0,8,0">
|
FontSize="11" FontWeight="SemiBold" Foreground="#8b949e"
|
||||||
<DockPanel>
|
Margin="0,0,0,4" />
|
||||||
<TextBlock DockPanel.Dock="Top" Text="TRADE LINKS"
|
<ScrollViewer x:Name="LogScroll">
|
||||||
FontSize="11" FontWeight="SemiBold" Foreground="#8b949e"
|
<SelectableTextBlock x:Name="LogBlock"
|
||||||
Margin="0,0,0,8" />
|
FontSize="11" FontFamily="Consolas"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
<!-- Add link form -->
|
</ScrollViewer>
|
||||||
<StackPanel DockPanel.Dock="Top" Spacing="6" Margin="0,0,0,8">
|
</DockPanel>
|
||||||
<TextBox Text="{Binding NewLinkName}" Watermark="Name (optional)" />
|
</Border>
|
||||||
<TextBox Text="{Binding NewUrl}" Watermark="Paste trade URL..." />
|
|
||||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
|
||||||
<ComboBox ItemsSource="{x:Static vm:MainWindowViewModel.LinkModes}"
|
|
||||||
SelectedItem="{Binding NewLinkMode}" Width="100" />
|
|
||||||
<Button Content="Add" Command="{Binding AddLinkCommand}" />
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<!-- Links list -->
|
|
||||||
<ScrollViewer>
|
|
||||||
<ItemsControl ItemsSource="{Binding Links}">
|
|
||||||
<ItemsControl.ItemTemplate>
|
|
||||||
<DataTemplate>
|
|
||||||
<Border Margin="0,2" Padding="8" Background="#21262d"
|
|
||||||
CornerRadius="4"
|
|
||||||
Opacity="{Binding Active, Converter={StaticResource ActiveOpacity}}">
|
|
||||||
<DockPanel>
|
|
||||||
<Button DockPanel.Dock="Right" Content="X" FontSize="10"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Command="{Binding $parent[ItemsControl].((vm:MainWindowViewModel)DataContext).RemoveLinkCommand}"
|
|
||||||
CommandParameter="{Binding Id}" />
|
|
||||||
<CheckBox DockPanel.Dock="Left"
|
|
||||||
IsChecked="{Binding Active}"
|
|
||||||
Margin="0,0,8,0" VerticalAlignment="Center" />
|
|
||||||
<StackPanel>
|
|
||||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
|
||||||
<Border Background="{Binding Mode, Converter={StaticResource ModeBrush}}"
|
|
||||||
CornerRadius="4" Padding="6,2">
|
|
||||||
<TextBlock Text="{Binding Mode}"
|
|
||||||
FontSize="10" FontWeight="Bold"
|
|
||||||
Foreground="White" />
|
|
||||||
</Border>
|
|
||||||
<TextBlock Text="{Binding Name}" FontSize="12"
|
|
||||||
FontWeight="SemiBold" Foreground="#e6edf3" />
|
|
||||||
</StackPanel>
|
|
||||||
<TextBlock Text="{Binding Label}" FontSize="10"
|
|
||||||
Foreground="#8b949e" TextTrimming="CharacterEllipsis" />
|
|
||||||
</StackPanel>
|
|
||||||
</DockPanel>
|
|
||||||
</Border>
|
|
||||||
</DataTemplate>
|
|
||||||
</ItemsControl.ItemTemplate>
|
|
||||||
</ItemsControl>
|
|
||||||
</ScrollViewer>
|
|
||||||
</DockPanel>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<!-- Right: Logs -->
|
|
||||||
<Border Grid.Column="1" Background="#161b22" BorderBrush="#30363d"
|
|
||||||
BorderThickness="1" CornerRadius="8" Padding="10">
|
|
||||||
<DockPanel>
|
|
||||||
<TextBlock DockPanel.Dock="Top" Text="ACTIVITY LOG"
|
|
||||||
FontSize="11" FontWeight="SemiBold" Foreground="#8b949e"
|
|
||||||
Margin="0,0,0,8" />
|
|
||||||
<ListBox ItemsSource="{Binding Logs}" x:Name="LogList"
|
|
||||||
Background="Transparent" BorderThickness="0">
|
|
||||||
<ListBox.ItemTemplate>
|
|
||||||
<DataTemplate x:DataType="vm:LogEntry">
|
|
||||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
|
||||||
<TextBlock Text="{Binding Time}" Foreground="#484f58"
|
|
||||||
FontSize="11" FontFamily="Consolas" />
|
|
||||||
<TextBlock Text="{Binding Message}" FontSize="11"
|
|
||||||
FontFamily="Consolas" TextWrapping="Wrap"
|
|
||||||
Foreground="{Binding Level, Converter={StaticResource LogLevelBrush}}" />
|
|
||||||
</StackPanel>
|
|
||||||
</DataTemplate>
|
|
||||||
</ListBox.ItemTemplate>
|
|
||||||
</ListBox>
|
|
||||||
</DockPanel>
|
|
||||||
</Border>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|
||||||
|
<!-- ========== TRADE TAB ========== -->
|
||||||
|
<TabItem Header="Trade">
|
||||||
|
<Border Background="#161b22" BorderBrush="#30363d"
|
||||||
|
BorderThickness="1" CornerRadius="8" Padding="8" Margin="0,6,0,0">
|
||||||
|
<DockPanel>
|
||||||
|
<TextBlock DockPanel.Dock="Top" Text="TRADE LINKS"
|
||||||
|
FontSize="11" FontWeight="SemiBold" Foreground="#8b949e"
|
||||||
|
Margin="0,0,0,4" />
|
||||||
|
|
||||||
|
<!-- Add link form -->
|
||||||
|
<StackPanel DockPanel.Dock="Top" Spacing="4" Margin="0,0,0,6">
|
||||||
|
<TextBox Text="{Binding NewLinkName}" Watermark="Name (optional)" />
|
||||||
|
<TextBox Text="{Binding NewUrl}" Watermark="Paste trade URL..." />
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||||
|
<ComboBox ItemsSource="{x:Static vm:MainWindowViewModel.LinkModes}"
|
||||||
|
SelectedItem="{Binding NewLinkMode}" Width="100" />
|
||||||
|
<Button Content="Add" Command="{Binding AddLinkCommand}" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Links list -->
|
||||||
|
<ScrollViewer>
|
||||||
|
<ItemsControl ItemsSource="{Binding Links}">
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Border Margin="0,2" Padding="6" Background="#21262d"
|
||||||
|
CornerRadius="4"
|
||||||
|
Opacity="{Binding Active, Converter={StaticResource ActiveOpacity}}">
|
||||||
|
<DockPanel>
|
||||||
|
<Button DockPanel.Dock="Right" Content="X" FontSize="10"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Command="{Binding $parent[ItemsControl].((vm:MainWindowViewModel)DataContext).RemoveLinkCommand}"
|
||||||
|
CommandParameter="{Binding Id}" />
|
||||||
|
<CheckBox DockPanel.Dock="Left"
|
||||||
|
IsChecked="{Binding Active}"
|
||||||
|
Margin="0,0,8,0" VerticalAlignment="Center" />
|
||||||
|
<StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||||
|
<Border Background="{Binding Mode, Converter={StaticResource ModeBrush}}"
|
||||||
|
CornerRadius="4" Padding="6,2">
|
||||||
|
<TextBlock Text="{Binding Mode}"
|
||||||
|
FontSize="10" FontWeight="Bold"
|
||||||
|
Foreground="White" />
|
||||||
|
</Border>
|
||||||
|
<TextBlock Text="{Binding Name}" FontSize="12"
|
||||||
|
FontWeight="SemiBold" Foreground="#e6edf3" />
|
||||||
|
</StackPanel>
|
||||||
|
<TextBlock Text="{Binding Label}" FontSize="10"
|
||||||
|
Foreground="#8b949e" TextTrimming="CharacterEllipsis" />
|
||||||
|
</StackPanel>
|
||||||
|
</DockPanel>
|
||||||
|
</Border>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</ScrollViewer>
|
||||||
|
</DockPanel>
|
||||||
|
</Border>
|
||||||
|
</TabItem>
|
||||||
|
|
||||||
<!-- ========== DEBUG TAB ========== -->
|
<!-- ========== DEBUG TAB ========== -->
|
||||||
<TabItem Header="Debug">
|
<TabItem Header="Debug">
|
||||||
<ScrollViewer DataContext="{Binding DebugVm}" Margin="0,8,0,0">
|
<ScrollViewer DataContext="{Binding DebugVm}" Margin="0,6,0,0">
|
||||||
<StackPanel Spacing="12" Margin="8" x:DataType="vm:DebugViewModel">
|
<StackPanel Spacing="8" Margin="6" x:DataType="vm:DebugViewModel">
|
||||||
|
|
||||||
<!-- Row 1: Quick actions -->
|
<!-- Row 1: Quick actions -->
|
||||||
<Border Background="#161b22" BorderBrush="#30363d" BorderThickness="1"
|
<Border Background="#161b22" BorderBrush="#30363d" BorderThickness="1"
|
||||||
CornerRadius="8" Padding="12">
|
CornerRadius="8" Padding="8">
|
||||||
<StackPanel Spacing="8">
|
<StackPanel Spacing="6">
|
||||||
<TextBlock Text="QUICK ACTIONS" FontSize="11" FontWeight="SemiBold"
|
<TextBlock Text="QUICK ACTIONS" FontSize="11" FontWeight="SemiBold"
|
||||||
Foreground="#8b949e" />
|
Foreground="#8b949e" />
|
||||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||||
|
|
@ -211,8 +204,8 @@
|
||||||
|
|
||||||
<!-- Row 2: Find text -->
|
<!-- Row 2: Find text -->
|
||||||
<Border Background="#161b22" BorderBrush="#30363d" BorderThickness="1"
|
<Border Background="#161b22" BorderBrush="#30363d" BorderThickness="1"
|
||||||
CornerRadius="8" Padding="12">
|
CornerRadius="8" Padding="8">
|
||||||
<StackPanel Spacing="8">
|
<StackPanel Spacing="6">
|
||||||
<TextBlock Text="FIND TEXT" FontSize="11" FontWeight="SemiBold"
|
<TextBlock Text="FIND TEXT" FontSize="11" FontWeight="SemiBold"
|
||||||
Foreground="#8b949e" />
|
Foreground="#8b949e" />
|
||||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||||
|
|
@ -226,8 +219,8 @@
|
||||||
|
|
||||||
<!-- Row 3: Grid scan -->
|
<!-- Row 3: Grid scan -->
|
||||||
<Border Background="#161b22" BorderBrush="#30363d" BorderThickness="1"
|
<Border Background="#161b22" BorderBrush="#30363d" BorderThickness="1"
|
||||||
CornerRadius="8" Padding="12">
|
CornerRadius="8" Padding="8">
|
||||||
<StackPanel Spacing="8">
|
<StackPanel Spacing="6">
|
||||||
<TextBlock Text="GRID SCAN" FontSize="11" FontWeight="SemiBold"
|
<TextBlock Text="GRID SCAN" FontSize="11" FontWeight="SemiBold"
|
||||||
Foreground="#8b949e" />
|
Foreground="#8b949e" />
|
||||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||||
|
|
@ -240,8 +233,8 @@
|
||||||
|
|
||||||
<!-- Row 4: Click At -->
|
<!-- Row 4: Click At -->
|
||||||
<Border Background="#161b22" BorderBrush="#30363d" BorderThickness="1"
|
<Border Background="#161b22" BorderBrush="#30363d" BorderThickness="1"
|
||||||
CornerRadius="8" Padding="12">
|
CornerRadius="8" Padding="8">
|
||||||
<StackPanel Spacing="8">
|
<StackPanel Spacing="6">
|
||||||
<TextBlock Text="CLICK AT POSITION" FontSize="11" FontWeight="SemiBold"
|
<TextBlock Text="CLICK AT POSITION" FontSize="11" FontWeight="SemiBold"
|
||||||
Foreground="#8b949e" />
|
Foreground="#8b949e" />
|
||||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||||
|
|
@ -256,10 +249,10 @@
|
||||||
|
|
||||||
<!-- Debug result output -->
|
<!-- Debug result output -->
|
||||||
<Border Background="#161b22" BorderBrush="#30363d" BorderThickness="1"
|
<Border Background="#161b22" BorderBrush="#30363d" BorderThickness="1"
|
||||||
CornerRadius="8" Padding="12" MinHeight="60">
|
CornerRadius="8" Padding="8">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBlock Text="OUTPUT" FontSize="11" FontWeight="SemiBold"
|
<TextBlock Text="OUTPUT" FontSize="11" FontWeight="SemiBold"
|
||||||
Foreground="#8b949e" Margin="0,0,0,6" />
|
Foreground="#8b949e" Margin="0,0,0,4" />
|
||||||
<TextBlock Text="{Binding DebugResult}" FontFamily="Consolas"
|
<TextBlock Text="{Binding DebugResult}" FontFamily="Consolas"
|
||||||
FontSize="11" Foreground="#e6edf3" TextWrapping="Wrap" />
|
FontSize="11" Foreground="#e6edf3" TextWrapping="Wrap" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
@ -270,13 +263,13 @@
|
||||||
|
|
||||||
<!-- ========== SETTINGS TAB ========== -->
|
<!-- ========== SETTINGS TAB ========== -->
|
||||||
<TabItem Header="Settings">
|
<TabItem Header="Settings">
|
||||||
<ScrollViewer DataContext="{Binding SettingsVm}" Margin="0,8,0,0">
|
<ScrollViewer DataContext="{Binding SettingsVm}" Margin="0,6,0,0">
|
||||||
<StackPanel Spacing="12" Margin="8" MaxWidth="600"
|
<StackPanel Spacing="8" Margin="6" MaxWidth="600"
|
||||||
x:DataType="vm:SettingsViewModel">
|
x:DataType="vm:SettingsViewModel">
|
||||||
|
|
||||||
<Border Background="#161b22" BorderBrush="#30363d" BorderThickness="1"
|
<Border Background="#161b22" BorderBrush="#30363d" BorderThickness="1"
|
||||||
CornerRadius="8" Padding="16">
|
CornerRadius="8" Padding="10">
|
||||||
<StackPanel Spacing="12">
|
<StackPanel Spacing="8">
|
||||||
<TextBlock Text="GENERAL SETTINGS" FontSize="11" FontWeight="SemiBold"
|
<TextBlock Text="GENERAL SETTINGS" FontSize="11" FontWeight="SemiBold"
|
||||||
Foreground="#8b949e" />
|
Foreground="#8b949e" />
|
||||||
|
|
||||||
|
|
@ -291,29 +284,32 @@
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<Grid ColumnDefinitions="*,*" RowDefinitions="Auto,Auto">
|
<Grid ColumnDefinitions="*,*" RowDefinitions="Auto,Auto">
|
||||||
<StackPanel Grid.Row="0" Grid.Column="0" Spacing="4" Margin="0,0,6,8">
|
<StackPanel Grid.Row="0" Grid.Column="0" Spacing="4" Margin="0,0,4,6">
|
||||||
<TextBlock Text="Travel Timeout (ms)" FontSize="11" Foreground="#8b949e" />
|
<TextBlock Text="Travel Timeout (ms)" FontSize="11" Foreground="#8b949e" />
|
||||||
<NumericUpDown Value="{Binding TravelTimeoutMs}" Minimum="1000"
|
<NumericUpDown Value="{Binding TravelTimeoutMs}" Minimum="1000"
|
||||||
Maximum="60000" Increment="1000" />
|
Maximum="60000" Increment="1000" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Grid.Row="0" Grid.Column="1" Spacing="4" Margin="6,0,0,8">
|
<StackPanel Grid.Row="0" Grid.Column="1" Spacing="4" Margin="4,0,0,6">
|
||||||
<TextBlock Text="Stash Scan Timeout (ms)" FontSize="11" Foreground="#8b949e" />
|
<TextBlock Text="Stash Scan Timeout (ms)" FontSize="11" Foreground="#8b949e" />
|
||||||
<NumericUpDown Value="{Binding StashScanTimeoutMs}" Minimum="1000"
|
<NumericUpDown Value="{Binding StashScanTimeoutMs}" Minimum="1000"
|
||||||
Maximum="60000" Increment="1000" />
|
Maximum="60000" Increment="1000" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Grid.Row="1" Grid.Column="0" Spacing="4" Margin="0,0,6,0">
|
<StackPanel Grid.Row="1" Grid.Column="0" Spacing="4" Margin="0,0,4,0">
|
||||||
<TextBlock Text="Wait for More Items (ms)" FontSize="11" Foreground="#8b949e" />
|
<TextBlock Text="Wait for More Items (ms)" FontSize="11" Foreground="#8b949e" />
|
||||||
<NumericUpDown Value="{Binding WaitForMoreItemsMs}" Minimum="1000"
|
<NumericUpDown Value="{Binding WaitForMoreItemsMs}" Minimum="1000"
|
||||||
Maximum="120000" Increment="1000" />
|
Maximum="120000" Increment="1000" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Grid.Row="1" Grid.Column="1" Spacing="4" Margin="6,0,0,0">
|
<StackPanel Grid.Row="1" Grid.Column="1" Spacing="4" Margin="4,0,0,0">
|
||||||
<TextBlock Text="Delay Between Trades (ms)" FontSize="11" Foreground="#8b949e" />
|
<TextBlock Text="Delay Between Trades (ms)" FontSize="11" Foreground="#8b949e" />
|
||||||
<NumericUpDown Value="{Binding BetweenTradesDelayMs}" Minimum="0"
|
<NumericUpDown Value="{Binding BetweenTradesDelayMs}" Minimum="0"
|
||||||
Maximum="60000" Increment="1000" />
|
Maximum="60000" Increment="1000" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<StackPanel Orientation="Horizontal" Spacing="8" Margin="0,4,0,0">
|
<CheckBox IsChecked="{Binding Headless}" Content="Headless browser"
|
||||||
|
Foreground="#e6edf3" Margin="0,4,0,0" />
|
||||||
|
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="8" Margin="0,2,0,0">
|
||||||
<Button Content="Save Settings" Command="{Binding SaveSettingsCommand}" />
|
<Button Content="Save Settings" Command="{Binding SaveSettingsCommand}" />
|
||||||
<TextBlock Text="Saved!" Foreground="#3fb950" VerticalAlignment="Center"
|
<TextBlock Text="Saved!" Foreground="#3fb950" VerticalAlignment="Center"
|
||||||
IsVisible="{Binding IsSaved}" FontWeight="SemiBold" />
|
IsVisible="{Binding IsSaved}" FontWeight="SemiBold" />
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.Documents;
|
||||||
|
using Avalonia.Media;
|
||||||
using Poe2Trade.Core;
|
using Poe2Trade.Core;
|
||||||
using Poe2Trade.Ui.ViewModels;
|
using Poe2Trade.Ui.ViewModels;
|
||||||
|
|
||||||
|
|
@ -10,6 +12,13 @@ public partial class MainWindow : Window
|
||||||
{
|
{
|
||||||
private ConfigStore? _store;
|
private ConfigStore? _store;
|
||||||
|
|
||||||
|
private static readonly IBrush TimeBrush = new SolidColorBrush(Color.Parse("#484f58"));
|
||||||
|
private static readonly IBrush InfoBrush = new SolidColorBrush(Color.Parse("#58a6ff"));
|
||||||
|
private static readonly IBrush WarnBrush = new SolidColorBrush(Color.Parse("#d29922"));
|
||||||
|
private static readonly IBrush ErrorBrush = new SolidColorBrush(Color.Parse("#f85149"));
|
||||||
|
private static readonly IBrush DebugBrush = new SolidColorBrush(Color.Parse("#8b949e"));
|
||||||
|
private static readonly IBrush DefaultBrush = new SolidColorBrush(Color.Parse("#e6edf3"));
|
||||||
|
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
@ -42,16 +51,58 @@ public partial class MainWindow : Window
|
||||||
{
|
{
|
||||||
vm.Logs.CollectionChanged += (_, args) =>
|
vm.Logs.CollectionChanged += (_, args) =>
|
||||||
{
|
{
|
||||||
if (args.Action == NotifyCollectionChangedAction.Add)
|
var block = this.FindControl<SelectableTextBlock>("LogBlock");
|
||||||
|
var scroll = this.FindControl<ScrollViewer>("LogScroll");
|
||||||
|
if (block == null) return;
|
||||||
|
|
||||||
|
if (args.Action == NotifyCollectionChangedAction.Add && args.NewItems != null)
|
||||||
{
|
{
|
||||||
var logList = this.FindControl<ListBox>("LogList");
|
foreach (LogEntry entry in args.NewItems)
|
||||||
if (logList != null && vm.Logs.Count > 0)
|
AppendLogEntry(block, entry);
|
||||||
logList.ScrollIntoView(vm.Logs[^1]);
|
|
||||||
}
|
}
|
||||||
|
else if (args.Action == NotifyCollectionChangedAction.Remove)
|
||||||
|
{
|
||||||
|
// Rebuild when old entries trimmed
|
||||||
|
RebuildLog(block, vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
scroll?.ScrollToEnd();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void AppendLogEntry(SelectableTextBlock block, LogEntry entry)
|
||||||
|
{
|
||||||
|
if (block.Inlines?.Count > 0)
|
||||||
|
block.Inlines.Add(new Run("\n"));
|
||||||
|
|
||||||
|
block.Inlines ??= [];
|
||||||
|
block.Inlines.Add(new Run(entry.Time + " ") { Foreground = TimeBrush });
|
||||||
|
block.Inlines.Add(new Run(entry.Message) { Foreground = LevelBrush(entry.Level) });
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RebuildLog(SelectableTextBlock block, MainWindowViewModel vm)
|
||||||
|
{
|
||||||
|
block.Inlines?.Clear();
|
||||||
|
block.Inlines ??= [];
|
||||||
|
for (var i = 0; i < vm.Logs.Count; i++)
|
||||||
|
{
|
||||||
|
if (i > 0) block.Inlines.Add(new Run("\n"));
|
||||||
|
var entry = vm.Logs[i];
|
||||||
|
block.Inlines.Add(new Run(entry.Time + " ") { Foreground = TimeBrush });
|
||||||
|
block.Inlines.Add(new Run(entry.Message) { Foreground = LevelBrush(entry.Level) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IBrush LevelBrush(string level) => level switch
|
||||||
|
{
|
||||||
|
"INFO" => InfoBrush,
|
||||||
|
"WARN" or "WARNING" => WarnBrush,
|
||||||
|
"ERROR" => ErrorBrush,
|
||||||
|
"DEBUG" => DebugBrush,
|
||||||
|
_ => DefaultBrush,
|
||||||
|
};
|
||||||
|
|
||||||
protected override void OnClosing(WindowClosingEventArgs e)
|
protected override void OnClosing(WindowClosingEventArgs e)
|
||||||
{
|
{
|
||||||
if (_store != null)
|
if (_store != null)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue