using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; using AudibleApi; using AudibleUtilities; namespace LibationWinForms.Dialogs { public partial class AccountsDialog : Form { private const string COL_Delete = nameof(DeleteAccount); private const string COL_LibraryScan = nameof(LibraryScan); private const string COL_AccountId = nameof(AccountId); private const string COL_AccountName = nameof(AccountName); private const string COL_Locale = nameof(Locale); public AccountsDialog() { InitializeComponent(); dataGridView1.Columns[COL_AccountName].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; populateDropDown(); populateGridValues(); this.SetLibationIcon(); } private void populateDropDown() => (dataGridView1.Columns[COL_Locale] as DataGridViewComboBoxColumn).DataSource = Localization.Locales .Select(l => l.Name) .OrderBy(a => a).ToList(); private void populateGridValues() { // WARNING: accounts persister will write ANY EDIT to object immediately to file // here: copy strings and dispose of persister // only persist in 'save' step using var persister = AudibleApiStorage.GetAccountsSettingsPersister(); var accounts = persister.AccountsSettings.Accounts; if (!accounts.Any()) return; foreach (var account in accounts) dataGridView1.Rows.Add( "X", account.LibraryScan, account.AccountId, account.Locale.Name, account.AccountName); } private void dataGridView1_DefaultValuesNeeded(object sender, DataGridViewRowEventArgs e) { e.Row.Cells[COL_Delete].Value = "X"; e.Row.Cells[COL_LibraryScan].Value = true; } private void DataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e) { var dgv = (DataGridView)sender; var col = dgv.Columns[e.ColumnIndex]; if (col is DataGridViewButtonColumn && e.RowIndex >= 0) { var row = dgv.Rows[e.RowIndex]; switch (col.Name) { case COL_Delete: // if final/edit row: do nothing if (e.RowIndex < dgv.RowCount - 1) dgv.Rows.Remove(row); break; //case COL_MoveUp: // // if top: do nothing // if (e.RowIndex < 1) // break; // dgv.Rows.Remove(row); // dgv.Rows.Insert(e.RowIndex - 1, row); // break; //case COL_MoveDown: // // if final/edit row or bottom filter row: do nothing // if (e.RowIndex >= dgv.RowCount - 2) // break; // dgv.Rows.Remove(row); // dgv.Rows.Insert(e.RowIndex + 1, row); // break; } } } private void cancelBtn_Click(object sender, EventArgs e) { this.DialogResult = DialogResult.Cancel; this.Close(); } private class AccountDto { public string AccountId { get; set; } public string AccountName { get; set; } public string LocaleName { get; set; } public bool LibraryScan { get; set; } } private void saveBtn_Click(object sender, EventArgs e) { try { if (!inputIsValid()) return; // without transaction, accounts persister will write ANY EDIT immediately to file using var persister = AudibleApiStorage.GetAccountsSettingsPersister(); persister.BeginTransation(); persist(persister.AccountsSettings); persister.CommitTransation(); this.DialogResult = DialogResult.OK; this.Close(); } catch (Exception ex) { MessageBoxLib.ShowAdminAlert(this, "Error attempting to save accounts", "Error saving accounts", ex); } } private bool inputIsValid() { var dtos = getRowDtos(); foreach (var dto in dtos) { if (string.IsNullOrWhiteSpace(dto.AccountId)) { MessageBox.Show("Account id cannot be blank. Please enter an account id for all accounts.", "Blank account", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } if (string.IsNullOrWhiteSpace(dto.LocaleName)) { MessageBox.Show("Please select a locale (i.e.: country or region) for all accounts.", "Blank region", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } } return true; } private void persist(AccountsSettings accountsSettings) { var existingAccounts = accountsSettings.Accounts; var dtos = getRowDtos(); // editing account id is a special case. an account is defined by its account id, therefore this is really a different account. the user won't care about this distinction though. // these will be caught below by normal means and re-created minus the convenience of persisting identity tokens // delete for (var i = existingAccounts.Count - 1; i >= 0; i--) { var existing = existingAccounts[i]; if (!dtos.Any(dto => dto.AccountId?.ToLower().Trim() == existing.AccountId.ToLower() && dto.LocaleName == existing.Locale?.Name)) { accountsSettings.Delete(existing); } } // upsert each. validation occurs through Account and AccountsSettings foreach (var dto in dtos) { var acct = accountsSettings.Upsert(dto.AccountId, dto.LocaleName); acct.LibraryScan = dto.LibraryScan; acct.AccountName = string.IsNullOrWhiteSpace(dto.AccountName) ? $"{dto.AccountId} - {dto.LocaleName}" : dto.AccountName.Trim(); } } private List getRowDtos() => dataGridView1.Rows .Cast() .Where(r => !r.IsNewRow) .Select(r => new AccountDto { AccountId = (string)r.Cells[COL_AccountId].Value, AccountName = (string)r.Cells[COL_AccountName].Value, LocaleName = (string)r.Cells[COL_Locale].Value, LibraryScan = (bool)r.Cells[COL_LibraryScan].Value }) .ToList(); } }