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;
|
||||
|
||||
Emit("info", "Checking inventory for leftover items...");
|
||||
await Inventory.ClearToStash();
|
||||
Emit("info", "Inventory cleared");
|
||||
|
||||
// Wire executor events
|
||||
TradeExecutor.StateChanged += _ => UpdateExecutorState();
|
||||
TradeQueue.TradeCompleted += () => { _tradesCompleted++; 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
|
||||
var allUrls = new HashSet<string>(cliUrls);
|
||||
|
|
@ -207,7 +210,6 @@ public class BotOrchestrator : IAsyncDisposable
|
|||
// Wire trade monitor events
|
||||
TradeMonitor.NewListings += OnNewListings;
|
||||
|
||||
_started = true;
|
||||
Emit("info", $"Loaded {allUrls.Count} trade link(s)");
|
||||
Log.Information("Bot started");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ public class SavedSettings
|
|||
public double? WindowY { get; set; }
|
||||
public double? WindowWidth { get; set; }
|
||||
public double? WindowHeight { get; set; }
|
||||
public bool Headless { get; set; } = true;
|
||||
}
|
||||
|
||||
public class ConfigStore
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ namespace Poe2Trade.Inventory;
|
|||
|
||||
public interface IInventoryManager
|
||||
{
|
||||
event Action? Updated;
|
||||
InventoryTracker Tracker { get; }
|
||||
byte[]? LastScreenshot { get; }
|
||||
bool IsAtOwnHideout { get; }
|
||||
string SellerAccount { get; }
|
||||
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");
|
||||
|
||||
public event Action? Updated;
|
||||
public InventoryTracker Tracker { get; } = new();
|
||||
|
||||
private bool _atOwnHideout = true;
|
||||
|
|
@ -19,6 +20,7 @@ public class InventoryManager : IInventoryManager
|
|||
private readonly IClientLogWatcher _logWatcher;
|
||||
private readonly SavedSettings _config;
|
||||
|
||||
public byte[]? LastScreenshot { get; private set; }
|
||||
public bool IsAtOwnHideout => _atOwnHideout;
|
||||
public string SellerAccount => _sellerAccount;
|
||||
|
||||
|
|
@ -44,6 +46,7 @@ public class InventoryManager : IInventoryManager
|
|||
await _game.OpenInventory();
|
||||
|
||||
var result = await _screen.Grid.Scan("inventory");
|
||||
LastScreenshot = await _screen.CaptureRegion(GridLayouts.Inventory.Region);
|
||||
|
||||
var cells = new bool[5, 12];
|
||||
foreach (var cell in result.Occupied)
|
||||
|
|
@ -52,6 +55,7 @@ public class InventoryManager : IInventoryManager
|
|||
cells[cell.Row, cell.Col] = true;
|
||||
}
|
||||
Tracker.InitFromScan(cells, result.Items, defaultAction);
|
||||
Updated?.Invoke();
|
||||
|
||||
await _game.PressEscape();
|
||||
await Helpers.Sleep(Delays.PostFocus);
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ public class TradeMonitor : ITradeMonitor
|
|||
_config.BrowserUserDataDir,
|
||||
new BrowserTypeLaunchPersistentContextOptions
|
||||
{
|
||||
Headless = false,
|
||||
Headless = _config.Headless,
|
||||
ViewportSize = null,
|
||||
Args = [
|
||||
"--disable-blink-features=AutomationControlled",
|
||||
|
|
|
|||
|
|
@ -13,5 +13,6 @@
|
|||
<conv:StatusDotBrushConverter x:Key="StatusDotBrush" />
|
||||
<conv:ActiveOpacityConverter x:Key="ActiveOpacity" />
|
||||
<conv:CellBorderConverter x:Key="CellBorderConverter" />
|
||||
<conv:BoolToOverlayBrushConverter x:Key="OccupiedOverlayBrush" />
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ public class LinkModeToColorConverter : IValueConverter
|
|||
{
|
||||
LinkMode.Live => new SolidColorBrush(Color.Parse("#1f6feb")),
|
||||
LinkMode.Scrap => new SolidColorBrush(Color.Parse("#9e6a03")),
|
||||
|
||||
_ => new SolidColorBrush(Color.Parse("#30363d")),
|
||||
};
|
||||
}
|
||||
|
|
@ -79,6 +80,20 @@ public class ActiveOpacityConverter : IValueConverter
|
|||
=> 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 object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using Avalonia.Media.Imaging;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Poe2Trade.Bot;
|
||||
|
|
@ -39,6 +41,8 @@ public partial class MainWindowViewModel : ObservableObject
|
|||
[NotifyCanExecuteChangedFor(nameof(PauseCommand))]
|
||||
private bool _isStarted;
|
||||
|
||||
[ObservableProperty] private Bitmap? _inventoryImage;
|
||||
|
||||
[ObservableProperty] private string _newUrl = "";
|
||||
[ObservableProperty] private string _newLinkName = "";
|
||||
[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));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ public partial class SettingsViewModel : ObservableObject
|
|||
[ObservableProperty] private decimal? _stashScanTimeoutMs = 10000;
|
||||
[ObservableProperty] private decimal? _waitForMoreItemsMs = 20000;
|
||||
[ObservableProperty] private decimal? _betweenTradesDelayMs = 5000;
|
||||
[ObservableProperty] private bool _headless = true;
|
||||
[ObservableProperty] private bool _isSaved;
|
||||
|
||||
public SettingsViewModel(BotOrchestrator bot)
|
||||
|
|
@ -31,6 +32,7 @@ public partial class SettingsViewModel : ObservableObject
|
|||
StashScanTimeoutMs = s.StashScanTimeoutMs;
|
||||
WaitForMoreItemsMs = s.WaitForMoreItemsMs;
|
||||
BetweenTradesDelayMs = s.BetweenTradesDelayMs;
|
||||
Headless = s.Headless;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
|
|
@ -44,6 +46,7 @@ public partial class SettingsViewModel : ObservableObject
|
|||
s.StashScanTimeoutMs = (int)(StashScanTimeoutMs ?? 10000);
|
||||
s.WaitForMoreItemsMs = (int)(WaitForMoreItemsMs ?? 20000);
|
||||
s.BetweenTradesDelayMs = (int)(BetweenTradesDelayMs ?? 5000);
|
||||
s.Headless = Headless;
|
||||
});
|
||||
|
||||
IsSaved = true;
|
||||
|
|
@ -55,4 +58,5 @@ public partial class SettingsViewModel : ObservableObject
|
|||
partial void OnStashScanTimeoutMsChanged(decimal? value) => IsSaved = false;
|
||||
partial void OnWaitForMoreItemsMsChanged(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"
|
||||
x:Class="Poe2Trade.Ui.Views.MainWindow"
|
||||
x:DataType="vm:MainWindowViewModel"
|
||||
Title="POE2 Trade Bot"
|
||||
Width="960" Height="720"
|
||||
Title="Automata"
|
||||
Width="960" Height="640"
|
||||
Background="#0d1117">
|
||||
|
||||
<DockPanel Margin="12">
|
||||
<DockPanel Margin="8">
|
||||
|
||||
<!-- 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"
|
||||
BorderThickness="1" CornerRadius="8">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||
|
|
@ -24,30 +24,30 @@
|
|||
</StackPanel>
|
||||
|
||||
<!-- Stats cards -->
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="16"
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="10"
|
||||
HorizontalAlignment="Center">
|
||||
<Border Background="#21262d" CornerRadius="6" Padding="16,8">
|
||||
<Border Background="#21262d" CornerRadius="6" Padding="10,4">
|
||||
<StackPanel HorizontalAlignment="Center">
|
||||
<TextBlock Text="{Binding ActiveLinksCount}"
|
||||
FontSize="20" FontWeight="Bold" Foreground="#58a6ff"
|
||||
FontSize="16" FontWeight="Bold" Foreground="#58a6ff"
|
||||
HorizontalAlignment="Center" />
|
||||
<TextBlock Text="ACTIVE LINKS" FontSize="10" Foreground="#8b949e"
|
||||
HorizontalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border Background="#21262d" CornerRadius="6" Padding="16,8">
|
||||
<Border Background="#21262d" CornerRadius="6" Padding="10,4">
|
||||
<StackPanel HorizontalAlignment="Center">
|
||||
<TextBlock Text="{Binding TradesCompleted}"
|
||||
FontSize="20" FontWeight="Bold" Foreground="#3fb950"
|
||||
FontSize="16" FontWeight="Bold" Foreground="#3fb950"
|
||||
HorizontalAlignment="Center" />
|
||||
<TextBlock Text="TRADES DONE" FontSize="10" Foreground="#8b949e"
|
||||
HorizontalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border Background="#21262d" CornerRadius="6" Padding="16,8">
|
||||
<Border Background="#21262d" CornerRadius="6" Padding="10,4">
|
||||
<StackPanel HorizontalAlignment="Center">
|
||||
<TextBlock Text="{Binding TradesFailed}"
|
||||
FontSize="20" FontWeight="Bold" Foreground="#f85149"
|
||||
FontSize="16" FontWeight="Bold" Foreground="#f85149"
|
||||
HorizontalAlignment="Center" />
|
||||
<TextBlock Text="FAILED" FontSize="10" Foreground="#8b949e"
|
||||
HorizontalAlignment="Center" />
|
||||
|
|
@ -66,134 +66,127 @@
|
|||
<!-- TABBED CONTENT -->
|
||||
<TabControl>
|
||||
|
||||
<!-- ========== MAIN TAB ========== -->
|
||||
<TabItem Header="Main">
|
||||
<Grid RowDefinitions="Auto,*" Margin="0,8,0,0">
|
||||
<!-- ========== STATE TAB ========== -->
|
||||
<TabItem Header="State">
|
||||
<Grid RowDefinitions="Auto,*" Margin="0,6,0,0">
|
||||
|
||||
<!-- Inventory Grid (12x5) -->
|
||||
<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>
|
||||
<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"
|
||||
Foreground="#8b949e" />
|
||||
<TextBlock Text="{Binding InventoryFreeCells, StringFormat='{}{0}/60 free'}"
|
||||
FontSize="11" Foreground="#8b949e" Margin="12,0,0,0" />
|
||||
</StackPanel>
|
||||
<ItemsControl ItemsSource="{Binding InventoryCells}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<UniformGrid Columns="12" Rows="5" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:CellState">
|
||||
<Border Margin="1" CornerRadius="2" Height="22"
|
||||
Background="{Binding IsOccupied, Converter={StaticResource OccupiedBrush}}"
|
||||
BorderBrush="#3fb950" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<Grid MaxHeight="170">
|
||||
<Image Source="{Binding InventoryImage}" Stretch="Uniform" />
|
||||
<ItemsControl ItemsSource="{Binding InventoryCells}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<UniformGrid Columns="12" Rows="5" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:CellState">
|
||||
<Border Margin="1" CornerRadius="2"
|
||||
Background="{Binding IsOccupied, Converter={StaticResource OccupiedOverlayBrush}}"
|
||||
BorderBrush="#3fb950"
|
||||
BorderThickness="{Binding Converter={StaticResource CellBorderConverter}}" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Links + Logs split -->
|
||||
<Grid Grid.Row="1" ColumnDefinitions="350,*">
|
||||
|
||||
<!-- Left: Trade Links -->
|
||||
<Border Grid.Column="0" Background="#161b22" BorderBrush="#30363d"
|
||||
BorderThickness="1" CornerRadius="8" Padding="10" Margin="0,0,8,0">
|
||||
<DockPanel>
|
||||
<TextBlock DockPanel.Dock="Top" Text="TRADE LINKS"
|
||||
FontSize="11" FontWeight="SemiBold" Foreground="#8b949e"
|
||||
Margin="0,0,0,8" />
|
||||
|
||||
<!-- Add link form -->
|
||||
<StackPanel DockPanel.Dock="Top" Spacing="6" Margin="0,0,0,8">
|
||||
<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="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>
|
||||
<!-- Logs -->
|
||||
<Border Grid.Row="1" Background="#0d1117" BorderBrush="#30363d"
|
||||
BorderThickness="1" CornerRadius="8" Padding="8">
|
||||
<DockPanel>
|
||||
<TextBlock DockPanel.Dock="Top" Text="ACTIVITY LOG"
|
||||
FontSize="11" FontWeight="SemiBold" Foreground="#8b949e"
|
||||
Margin="0,0,0,4" />
|
||||
<ScrollViewer x:Name="LogScroll">
|
||||
<SelectableTextBlock x:Name="LogBlock"
|
||||
FontSize="11" FontFamily="Consolas"
|
||||
TextWrapping="Wrap" />
|
||||
</ScrollViewer>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</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 ========== -->
|
||||
<TabItem Header="Debug">
|
||||
<ScrollViewer DataContext="{Binding DebugVm}" Margin="0,8,0,0">
|
||||
<StackPanel Spacing="12" Margin="8" x:DataType="vm:DebugViewModel">
|
||||
<ScrollViewer DataContext="{Binding DebugVm}" Margin="0,6,0,0">
|
||||
<StackPanel Spacing="8" Margin="6" x:DataType="vm:DebugViewModel">
|
||||
|
||||
<!-- Row 1: Quick actions -->
|
||||
<Border Background="#161b22" BorderBrush="#30363d" BorderThickness="1"
|
||||
CornerRadius="8" Padding="12">
|
||||
<StackPanel Spacing="8">
|
||||
CornerRadius="8" Padding="8">
|
||||
<StackPanel Spacing="6">
|
||||
<TextBlock Text="QUICK ACTIONS" FontSize="11" FontWeight="SemiBold"
|
||||
Foreground="#8b949e" />
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
|
|
@ -211,8 +204,8 @@
|
|||
|
||||
<!-- Row 2: Find text -->
|
||||
<Border Background="#161b22" BorderBrush="#30363d" BorderThickness="1"
|
||||
CornerRadius="8" Padding="12">
|
||||
<StackPanel Spacing="8">
|
||||
CornerRadius="8" Padding="8">
|
||||
<StackPanel Spacing="6">
|
||||
<TextBlock Text="FIND TEXT" FontSize="11" FontWeight="SemiBold"
|
||||
Foreground="#8b949e" />
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
|
|
@ -226,8 +219,8 @@
|
|||
|
||||
<!-- Row 3: Grid scan -->
|
||||
<Border Background="#161b22" BorderBrush="#30363d" BorderThickness="1"
|
||||
CornerRadius="8" Padding="12">
|
||||
<StackPanel Spacing="8">
|
||||
CornerRadius="8" Padding="8">
|
||||
<StackPanel Spacing="6">
|
||||
<TextBlock Text="GRID SCAN" FontSize="11" FontWeight="SemiBold"
|
||||
Foreground="#8b949e" />
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
|
|
@ -240,8 +233,8 @@
|
|||
|
||||
<!-- Row 4: Click At -->
|
||||
<Border Background="#161b22" BorderBrush="#30363d" BorderThickness="1"
|
||||
CornerRadius="8" Padding="12">
|
||||
<StackPanel Spacing="8">
|
||||
CornerRadius="8" Padding="8">
|
||||
<StackPanel Spacing="6">
|
||||
<TextBlock Text="CLICK AT POSITION" FontSize="11" FontWeight="SemiBold"
|
||||
Foreground="#8b949e" />
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
|
|
@ -256,10 +249,10 @@
|
|||
|
||||
<!-- Debug result output -->
|
||||
<Border Background="#161b22" BorderBrush="#30363d" BorderThickness="1"
|
||||
CornerRadius="8" Padding="12" MinHeight="60">
|
||||
CornerRadius="8" Padding="8">
|
||||
<StackPanel>
|
||||
<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"
|
||||
FontSize="11" Foreground="#e6edf3" TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
|
|
@ -270,13 +263,13 @@
|
|||
|
||||
<!-- ========== SETTINGS TAB ========== -->
|
||||
<TabItem Header="Settings">
|
||||
<ScrollViewer DataContext="{Binding SettingsVm}" Margin="0,8,0,0">
|
||||
<StackPanel Spacing="12" Margin="8" MaxWidth="600"
|
||||
<ScrollViewer DataContext="{Binding SettingsVm}" Margin="0,6,0,0">
|
||||
<StackPanel Spacing="8" Margin="6" MaxWidth="600"
|
||||
x:DataType="vm:SettingsViewModel">
|
||||
|
||||
<Border Background="#161b22" BorderBrush="#30363d" BorderThickness="1"
|
||||
CornerRadius="8" Padding="16">
|
||||
<StackPanel Spacing="12">
|
||||
CornerRadius="8" Padding="10">
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="GENERAL SETTINGS" FontSize="11" FontWeight="SemiBold"
|
||||
Foreground="#8b949e" />
|
||||
|
||||
|
|
@ -291,29 +284,32 @@
|
|||
</StackPanel>
|
||||
|
||||
<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" />
|
||||
<NumericUpDown Value="{Binding TravelTimeoutMs}" Minimum="1000"
|
||||
Maximum="60000" Increment="1000" />
|
||||
</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" />
|
||||
<NumericUpDown Value="{Binding StashScanTimeoutMs}" Minimum="1000"
|
||||
Maximum="60000" Increment="1000" />
|
||||
</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" />
|
||||
<NumericUpDown Value="{Binding WaitForMoreItemsMs}" Minimum="1000"
|
||||
Maximum="120000" Increment="1000" />
|
||||
</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" />
|
||||
<NumericUpDown Value="{Binding BetweenTradesDelayMs}" Minimum="0"
|
||||
Maximum="60000" Increment="1000" />
|
||||
</StackPanel>
|
||||
</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}" />
|
||||
<TextBlock Text="Saved!" Foreground="#3fb950" VerticalAlignment="Center"
|
||||
IsVisible="{Binding IsSaved}" FontWeight="SemiBold" />
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
using System.Collections.Specialized;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Documents;
|
||||
using Avalonia.Media;
|
||||
using Poe2Trade.Core;
|
||||
using Poe2Trade.Ui.ViewModels;
|
||||
|
||||
|
|
@ -10,6 +12,13 @@ public partial class MainWindow : Window
|
|||
{
|
||||
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()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
|
@ -42,16 +51,58 @@ public partial class MainWindow : Window
|
|||
{
|
||||
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");
|
||||
if (logList != null && vm.Logs.Count > 0)
|
||||
logList.ScrollIntoView(vm.Logs[^1]);
|
||||
foreach (LogEntry entry in args.NewItems)
|
||||
AppendLogEntry(block, entry);
|
||||
}
|
||||
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)
|
||||
{
|
||||
if (_store != null)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue