Phase 5-UI: Polymarket-Accounts-Tab (allgemeine Account-Verwaltung)

- tabPage2: DataGridView (Name/Wallet/Demo/Aktiv) + Toolstrip (Neuer Account/
  Loeschen) + PropertyGrid. Da AccountState jetzt general-only ist, zeigt das
  PropertyGrid automatisch nur die allgemeinen Felder (Wallet, API-Keys, Payouts).
- SettingsView.cs: Accounts laden, Auswahl -> PropertyGrid, Bearbeiten -> speichern
  (IAccountRepository + TradingState), Neu/Loeschen.
- Program.cs: Settings-View bekommt IAccountRepository + TradingState injiziert.
- Copytrading-Detail-Limits folgen im Modul-Account-View.
- Build 0 Fehler.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-07-03 10:35:20 +02:00
co-authored by Claude Opus 4.8
parent 095c4b64aa
commit 87dd9a750d
3 changed files with 188 additions and 5 deletions
+109
View File
@@ -26,9 +26,21 @@ namespace PolyTraderSharp.Ui.Views
toolStrip2 = new ToolStrip();
btn_save = new ToolStripButton();
btn_loadsettings = new ToolStripButton();
toolStripAccounts = new ToolStrip();
btnAccNew = new ToolStripButton();
btnAccDelete = new ToolStripButton();
dgvAccounts = new DataGridView();
colAccName = new DataGridViewTextBoxColumn();
colAccWallet = new DataGridViewTextBoxColumn();
colAccDemo = new DataGridViewCheckBoxColumn();
colAccActive = new DataGridViewCheckBoxColumn();
pgAccount = new PropertyGrid();
tabControl1.SuspendLayout();
tabPage1.SuspendLayout();
tabPage2.SuspendLayout();
toolStrip2.SuspendLayout();
toolStripAccounts.SuspendLayout();
((System.ComponentModel.ISupportInitialize)dgvAccounts).BeginInit();
SuspendLayout();
//
// propertyGrid
@@ -74,6 +86,9 @@ namespace PolyTraderSharp.Ui.Views
//
// tabPage2
//
tabPage2.Controls.Add(pgAccount);
tabPage2.Controls.Add(dgvAccounts);
tabPage2.Controls.Add(toolStripAccounts);
tabPage2.Location = new Point(4, 34);
tabPage2.Name = "tabPage2";
tabPage2.Padding = new Padding(3);
@@ -108,6 +123,86 @@ namespace PolyTraderSharp.Ui.Views
btn_loadsettings.Size = new Size(223, 29);
btn_loadsettings.Text = "Load Settings from File";
//
// toolStripAccounts
//
toolStripAccounts.ImageScalingSize = new Size(24, 24);
toolStripAccounts.Items.AddRange(new ToolStripItem[] { btnAccNew, btnAccDelete });
toolStripAccounts.Location = new Point(3, 3);
toolStripAccounts.Name = "toolStripAccounts";
toolStripAccounts.Size = new Size(1171, 34);
toolStripAccounts.TabIndex = 0;
//
// btnAccNew
//
btnAccNew.DisplayStyle = ToolStripItemDisplayStyle.Text;
btnAccNew.Name = "btnAccNew";
btnAccNew.Size = new Size(130, 29);
btnAccNew.Text = "Neuer Account";
//
// btnAccDelete
//
btnAccDelete.DisplayStyle = ToolStripItemDisplayStyle.Text;
btnAccDelete.Name = "btnAccDelete";
btnAccDelete.Size = new Size(90, 29);
btnAccDelete.Text = "Löschen";
//
// dgvAccounts
//
dgvAccounts.AllowUserToAddRows = false;
dgvAccounts.AllowUserToDeleteRows = false;
dgvAccounts.AutoGenerateColumns = false;
dgvAccounts.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
dgvAccounts.Columns.AddRange(new DataGridViewColumn[] { colAccName, colAccWallet, colAccDemo, colAccActive });
dgvAccounts.Dock = DockStyle.Left;
dgvAccounts.Location = new Point(3, 37);
dgvAccounts.MultiSelect = false;
dgvAccounts.Name = "dgvAccounts";
dgvAccounts.ReadOnly = true;
dgvAccounts.RowHeadersVisible = false;
dgvAccounts.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dgvAccounts.Size = new Size(620, 847);
dgvAccounts.TabIndex = 1;
//
// colAccName
//
colAccName.DataPropertyName = "Name";
colAccName.HeaderText = "Name";
colAccName.Name = "colAccName";
colAccName.ReadOnly = true;
colAccName.Width = 200;
//
// colAccWallet
//
colAccWallet.DataPropertyName = "WalletAddress";
colAccWallet.HeaderText = "Wallet";
colAccWallet.Name = "colAccWallet";
colAccWallet.ReadOnly = true;
colAccWallet.Width = 260;
//
// colAccDemo
//
colAccDemo.DataPropertyName = "IsDemo";
colAccDemo.HeaderText = "Demo";
colAccDemo.Name = "colAccDemo";
colAccDemo.ReadOnly = true;
colAccDemo.Width = 60;
//
// colAccActive
//
colAccActive.DataPropertyName = "IsActive";
colAccActive.HeaderText = "Aktiv";
colAccActive.Name = "colAccActive";
colAccActive.ReadOnly = true;
colAccActive.Width = 60;
//
// pgAccount
//
pgAccount.Dock = DockStyle.Fill;
pgAccount.Location = new Point(623, 37);
pgAccount.Name = "pgAccount";
pgAccount.Size = new Size(551, 847);
pgAccount.TabIndex = 2;
//
// SettingsView
//
AutoScaleDimensions = new SizeF(10F, 25F);
@@ -121,8 +216,13 @@ namespace PolyTraderSharp.Ui.Views
tabControl1.ResumeLayout(false);
tabPage1.ResumeLayout(false);
tabPage1.PerformLayout();
tabPage2.ResumeLayout(false);
tabPage2.PerformLayout();
toolStrip2.ResumeLayout(false);
toolStrip2.PerformLayout();
toolStripAccounts.ResumeLayout(false);
toolStripAccounts.PerformLayout();
((System.ComponentModel.ISupportInitialize)dgvAccounts).EndInit();
ResumeLayout(false);
PerformLayout();
}
@@ -137,5 +237,14 @@ namespace PolyTraderSharp.Ui.Views
private TabPage tabPage2;
private ToolStripButton btn_save;
private ToolStripButton btn_loadsettings;
private ToolStrip toolStripAccounts;
private ToolStripButton btnAccNew;
private ToolStripButton btnAccDelete;
private DataGridView dgvAccounts;
private DataGridViewTextBoxColumn colAccName;
private DataGridViewTextBoxColumn colAccWallet;
private DataGridViewCheckBoxColumn colAccDemo;
private DataGridViewCheckBoxColumn colAccActive;
private PropertyGrid pgAccount;
}
}
+76 -4
View File
@@ -1,14 +1,18 @@
using System;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
using PolyTrader.Core.Persistence;
using PolyTraderSharp.Models;
using PolyTraderSharp.Services;
namespace PolyTraderSharp.Ui.Views
{
/// <summary>
/// Core-Settings-Ansicht: bearbeitet die ServerSettings über ein PropertyGrid.
/// Designbar (siehe SettingsView.Designer.cs); Laufzeit-Abhängigkeiten via Initialize.
/// Verhalten entspricht dem bisherigen Settings-Tab (Speichern -> XML + Services neu laden).
/// Core-Settings-Fenster: allgemeine Server-Einstellungen (PropertyGrid) und die
/// allgemeine Verwaltung der Polymarket-Accounts (Wallets, API-Keys …).
/// Die copytrading-spezifischen Detail-Limits werden NICHT hier, sondern im
/// Copytrading-Modul-View bearbeitet (AccountState ist bewusst general-only).
/// </summary>
public partial class SettingsView : Form
{
@@ -19,21 +23,44 @@ namespace PolyTraderSharp.Ui.Views
private MullvadVpnService? _vpn;
private TerminalLogger? _logger;
private IAccountRepository? _accountRepo;
private TradingState? _state;
private BindingList<AccountState> _accounts = new();
public SettingsView()
{
InitializeComponent();
btn_save.Click += (_, _) => Save();
btn_loadsettings.Click += (_, _) => Reload();
btnAccNew.Click += (_, _) => AddAccount();
btnAccDelete.Click += (_, _) => DeleteAccount();
dgvAccounts.SelectionChanged += (_, _) =>
{
pgAccount.SelectedObject = dgvAccounts.CurrentRow?.DataBoundItem as AccountState;
};
pgAccount.PropertyValueChanged += (_, _) =>
{
if (pgAccount.SelectedObject is AccountState acc) SaveAccount(acc);
};
}
public void Initialize(ThreemaService threema, MullvadVpnService vpn, TerminalLogger logger)
public void Initialize(ThreemaService threema, MullvadVpnService vpn, TerminalLogger logger,
IAccountRepository accountRepo, TradingState state)
{
_threema = threema;
_vpn = vpn;
_logger = logger;
_accountRepo = accountRepo;
_state = state;
Reload();
LoadAccounts();
}
// ===== Server-Settings =====
private void Reload()
{
_settings = ServerSettings.Load(SettingsPath);
@@ -57,5 +84,50 @@ namespace PolyTraderSharp.Ui.Views
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
// ===== Polymarket Accounts (allgemeine Einstellungen) =====
private void LoadAccounts()
{
if (_state == null) return;
_accounts = new BindingList<AccountState>(_state.Accounts.Values.OrderBy(a => a.AccountId).ToList());
dgvAccounts.DataSource = _accounts;
pgAccount.SelectedObject = dgvAccounts.CurrentRow?.DataBoundItem as AccountState;
}
private void AddAccount()
{
if (_state == null || _accountRepo == null) return;
int newId = _state.Accounts.Count > 0 ? _state.Accounts.Keys.Max() + 1 : 1;
var acc = new AccountState { AccountId = newId, Name = "Neuer Account" };
_state.Accounts[acc.AccountId] = acc;
_accountRepo.Upsert(acc);
_accounts.Add(acc);
dgvAccounts.CurrentCell = dgvAccounts.Rows[dgvAccounts.Rows.Count - 1].Cells[0];
}
private void DeleteAccount()
{
if (_state == null || _accountRepo == null) return;
if (dgvAccounts.CurrentRow?.DataBoundItem is not AccountState acc) return;
if (MessageBox.Show($"Account '{acc.Name}' (ID {acc.AccountId}) wirklich löschen?",
"Löschen bestätigen", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) != DialogResult.Yes)
return;
_state.Accounts.TryRemove(acc.AccountId, out _);
_accountRepo.Delete(acc.AccountId);
_accounts.Remove(acc);
}
private void SaveAccount(AccountState acc)
{
_accountRepo?.Upsert(acc);
_state?.Accounts.AddOrUpdate(acc.AccountId, acc, (_, _) => acc);
dgvAccounts.Refresh();
}
}
}