diff --git a/Program.cs b/Program.cs index 2b04c11..d642d4a 100644 --- a/Program.cs +++ b/Program.cs @@ -157,7 +157,9 @@ internal static class Program view.Initialize( viewServices.GetRequiredService(), viewServices.GetRequiredService(), - viewServices.GetRequiredService()); + viewServices.GetRequiredService(), + viewServices.GetRequiredService(), + viewServices.GetRequiredService()); return view; } }); diff --git a/Ui/Views/SettingsView.Designer.cs b/Ui/Views/SettingsView.Designer.cs index a927c86..ab9bc49 100644 --- a/Ui/Views/SettingsView.Designer.cs +++ b/Ui/Views/SettingsView.Designer.cs @@ -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; } } diff --git a/Ui/Views/SettingsView.cs b/Ui/Views/SettingsView.cs index cb59f3e..8dd1727 100644 --- a/Ui/Views/SettingsView.cs +++ b/Ui/Views/SettingsView.cs @@ -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 { /// - /// 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). /// 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 _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(_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(); + } } }