Compare commits

14 Commits

6 changed files with 654 additions and 1 deletions

View File

@@ -1,10 +1,404 @@
using System.Net.Http.Json;
namespace PizzaExpress_Client namespace PizzaExpress_Client
{ {
public partial class GestionePizzeForm : Form public partial class GestionePizzeForm : Form
{ {
private readonly HttpClient _httpClient;
private List<Pizza> _tutteLePizze = new();
private readonly ListBox _lstPizze;
private readonly TextBox _txtId, _txtNome, _txtPrezzo, _txtRicerca, _txtNote;
private readonly ComboBox _cmbCategoria, _cmbStato;
private readonly Button _btnAggiungi, _btnAggiorna, _btnElimina, _btnElenco, _btnCosto, _btnNuovaPizza;
public GestionePizzeForm() public GestionePizzeForm()
{ {
InitializeComponent(); Text = "Gestione Pizze (Database SQLite)";
// =============================
// DIMENSIONE FISSA DELLA FINESTRA
// =============================
Size = new Size(1000, 600);
MinimumSize = new Size(1000, 600);
MaximumSize = new Size(1000, 600);
FormBorderStyle = FormBorderStyle.FixedDialog;
MaximizeBox = false;
StartPosition = FormStartPosition.CenterScreen;
_httpClient = new HttpClient { BaseAddress = new Uri("http://localhost:5000/") };
// ======================================================
// PANNELLO SUPERIORE
// ======================================================
var pnlTop = new Panel
{
Dock = DockStyle.Top,
Height = 60
};
var lblTitolo = new Label
{
Text = "Gestione Pizze",
Font = new Font("Arial", 20, FontStyle.Bold),
Location = new Point(10, 15),
AutoSize = true
};
_btnCosto = new Button
{
Text = "Costo",
Location = new Point(900, 15),
Size = new Size(70, 30),
Enabled = false
};
_btnCosto.Click += BtnCosto_Click;
pnlTop.Controls.Add(lblTitolo);
pnlTop.Controls.Add(_btnCosto);
// ======================================================
// PANNELLO SINISTRO
// ======================================================
var pnlLeft = new Panel
{
Dock = DockStyle.Left,
Width = 300,
Padding = new Padding(10)
};
_txtRicerca = new TextBox
{
PlaceholderText = "Cerca pizza...",
Dock = DockStyle.Top,
Height = 30
};
_txtRicerca.TextChanged += (s, e) => FiltraPizze();
_btnElenco = new Button
{
Text = "Ricarica elenco",
Dock = DockStyle.Top,
Height = 35
};
_btnElenco.Click += async (s, e) => await CaricaPizze();
_lstPizze = new ListBox
{
Dock = DockStyle.Fill,
Font = new Font("Consolas", 10)
};
_lstPizze.SelectedIndexChanged += LstPizze_SelectedIndexChanged;
_btnNuovaPizza = new Button
{
Text = "Nuova pizza",
Dock = DockStyle.Bottom,
Height = 35
};
pnlLeft.Controls.Add(_lstPizze);
pnlLeft.Controls.Add(_btnElenco);
pnlLeft.Controls.Add(_txtRicerca);
pnlLeft.Controls.Add(_btnNuovaPizza);
// ======================================================
// PANNELLO DESTRO — ALLINEAMENTO PERFETTO A SINISTRA
// ======================================================
var pnlRight = new TableLayoutPanel
{
Dock = DockStyle.Fill,
ColumnCount = 2,
Padding = new Padding(10),
};
// Colonna etichette stretta, colonna input larga e allineata ai pulsanti
pnlRight.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 18));
pnlRight.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 82));
pnlRight.Controls.Add(new Label
{
Text = "Modifica pizza",
Font = new Font("Arial", 16, FontStyle.Bold),
AutoSize = true
}, 0, 0);
pnlRight.SetColumnSpan(pnlRight.GetControlFromPosition(0, 0), 2);
// ID
_txtId = new TextBox { Visible = false };
pnlRight.Controls.Add(new Label { Text = "Id:", Visible = false }, 0, 1);
pnlRight.Controls.Add(_txtId, 1, 1);
// Nome
pnlRight.Controls.Add(new Label { Text = "Nome:" }, 0, 2);
_txtNome = new TextBox
{
Width = 300,
Anchor = AnchorStyles.Left
};
pnlRight.Controls.Add(_txtNome, 1, 2);
// Prezzo
pnlRight.Controls.Add(new Label { Text = "Prezzo:" }, 0, 3);
_txtPrezzo = new TextBox
{
Width = 150,
Anchor = AnchorStyles.Left
};
pnlRight.Controls.Add(_txtPrezzo, 1, 3);
// Categoria
pnlRight.Controls.Add(new Label { Text = "Categoria:" }, 0, 4);
_cmbCategoria = new ComboBox
{
Width = 200,
DropDownStyle = ComboBoxStyle.DropDown,
Anchor = AnchorStyles.Left
};
_cmbCategoria.Items.AddRange(new[] { "Classica", "Speciale", "Gourmet" });
pnlRight.Controls.Add(_cmbCategoria, 1, 4);
// NOTE — Campo grande e allineato
pnlRight.Controls.Add(new Label { Text = "Note:" }, 0, 5);
_txtNote = new TextBox
{
Multiline = true,
Height = 230,
Width = 500,
ScrollBars = ScrollBars.Vertical,
Anchor = AnchorStyles.Left
};
pnlRight.Controls.Add(_txtNote, 1, 5);
//Stato
pnlRight.Controls.Add(new Label { Text = "Stato:" }, 0, 6);
_cmbStato = new ComboBox
{
Width = 200,
DropDownStyle = ComboBoxStyle.DropDown,
Anchor = AnchorStyles.Left
};
_cmbStato.Items.AddRange(new[] { "Rifiutata", "Ordinata", "In preparazione", "Preparata", "Servita"});
pnlRight.Controls.Add(_cmbStato, 1, 6);
// ======================================================
// PANNELLO PULSANTI — ALLINEATO COL CAMPO NOME (SX)
// ======================================================
var pnlButtons = new FlowLayoutPanel
{
FlowDirection = FlowDirection.LeftToRight,
AutoSize = true,
Anchor = AnchorStyles.Left,
Padding = new Padding(0, 10, 0, 0)
};
_btnAggiungi = new Button { Text = "Aggiungi", Width = 120, Enabled = false };
_btnAggiorna = new Button { Text = "Aggiorna", Width = 120, Enabled = false };
_btnElimina = new Button { Text = "Elimina", Width = 120, Enabled = false };
_btnAggiungi.Click += async (s, e) => await AggiungiPizza();
_btnAggiorna.Click += async (s, e) => await AggiornaPizza();
_btnElimina.Click += async (s, e) => await EliminaPizza();
_btnNuovaPizza.Click += (s, e) => PulisciCampi();
pnlButtons.Controls.Add(_btnAggiungi);
pnlButtons.Controls.Add(_btnAggiorna);
pnlButtons.Controls.Add(_btnElimina);
pnlRight.Controls.Add(pnlButtons, 1, 7);
// ======================================================
Controls.Add(pnlRight);
Controls.Add(pnlLeft);
Controls.Add(pnlTop);
Load += async (s, e) => await CaricaPizze();
var formUrl = new UrlForm(_httpClient.BaseAddress.ToString());
formUrl.Show();
}
// ======================================================================
private async Task CaricaPizze()
{
try
{
var pizze = await _httpClient.GetFromJsonAsync<List<Pizza>>("api/pizze");
_tutteLePizze = pizze ?? new List<Pizza>();
}
catch(Exception ex)
{
MessageBox.Show("Errore nella connessione al server.\n" + ex.Message);
_tutteLePizze = new List<Pizza>();
}
FiltraPizze();
}
private void FiltraPizze()
{
string filtro = _txtRicerca.Text.ToLower();
_lstPizze.Items.Clear();
foreach (var p in _tutteLePizze)
{
if (string.IsNullOrWhiteSpace(filtro) ||
p.Nome.ToLower().Contains(filtro) ||
p.Categoria.ToLower().Contains(filtro))
{
_lstPizze.Items.Add(p.ToString());
}
}
}
private void LstPizze_SelectedIndexChanged(object? sender, EventArgs e)
{
if (_lstPizze.SelectedIndex < 0)
return;
var p = _tutteLePizze[_lstPizze.SelectedIndex];
_txtId.Text = p.Id.ToString();
_txtNome.Text = p.Nome;
_txtPrezzo.Text = p.Prezzo.ToString();
_cmbCategoria.Text = p.Categoria;
_txtNote.Text = p.Note;
_cmbStato.Text = p.Stato;
_btnAggiungi.Enabled = false;
_btnElimina.Enabled = true;
_btnAggiorna.Enabled = true;
_btnCosto.Enabled = true;
}
// ======================================================================
private async Task AggiungiPizza()
{
if (!decimal.TryParse(_txtPrezzo.Text, out decimal prezzo))
{
MessageBox.Show("Prezzo non valido.");
return;
}
var pizza = new Pizza
{
Nome = _txtNome.Text,
Prezzo = prezzo,
Categoria = _cmbCategoria.Text,
Note = _txtNote.Text,
Stato = _cmbStato.Text
};
var resp = await _httpClient.PostAsJsonAsync("api/pizze", pizza);
if (!resp.IsSuccessStatusCode)
{
var err = await resp.Content.ReadFromJsonAsync<Dictionary<string, string>>();
MessageBox.Show(err["message"]);
return;
}
await CaricaPizze();
}
// ======================================================================
private async Task AggiornaPizza()
{
if (!int.TryParse(_txtId.Text, out int id))
{
MessageBox.Show("ID non valido.");
return;
}
if (!decimal.TryParse(_txtPrezzo.Text, out decimal prezzo))
{
MessageBox.Show("Prezzo non valido.");
return;
}
var pizza = new Pizza
{
Id = id,
Nome = _txtNome.Text,
Prezzo = prezzo,
Categoria = _cmbCategoria.Text,
Note = _txtNote.Text,
Stato = _cmbStato.Text
};
var resp = await _httpClient.PutAsJsonAsync($"api/pizze/{id}", pizza);
if (!resp.IsSuccessStatusCode)
{
var err = await resp.Content.ReadFromJsonAsync<Dictionary<string, string>>();
MessageBox.Show(err["message"]);
return;
}
await CaricaPizze();
}
// ======================================================================
private async Task EliminaPizza()
{
if (!int.TryParse(_txtId.Text, out int id))
{
MessageBox.Show("Seleziona una pizza da eliminare.");
}
else if (MessageBox.Show("Confermi l'eliminazione della pizza selezionata?", "Conferma eliminazione", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
await _httpClient.DeleteAsync($"api/pizze/{id}");
await CaricaPizze();
_lstPizze.ClearSelected();
_txtId.Clear();
_txtNome.Clear();
_txtPrezzo.Clear();
_txtNote.Clear();
_cmbCategoria.SelectedIndex = -1;
}
}
// ======================================================================
private void BtnCosto_Click(object? sender, EventArgs e)
{
if (_lstPizze.SelectedItem == null)
{
MessageBox.Show("Seleziona una pizza.");
return;
}
var s = _lstPizze.SelectedItem.ToString();
var parts = s.Split('-');
if (parts.Length >= 3)
{
string nome = parts[1].Trim();
string prezzo = parts[2].Replace("€", "").Trim();
MessageBox.Show($"La pizza {nome} costa {prezzo}€.");
}
}
private void PulisciCampi()
{
_txtId.Clear();
_txtNome.Clear();
_txtPrezzo.Clear();
_txtNote.Clear();
_cmbCategoria.SelectedIndex = -1;
_cmbStato.SelectedIndex = -1;
_btnAggiungi.Enabled = true;
_btnElimina.Enabled = false;
_btnAggiorna.Enabled = false;
_btnCosto.Enabled = false;
} }
} }
} }

25
LICENSE Normal file
View File

@@ -0,0 +1,25 @@
GLWT(Good Luck With That) Public License
Copyright (c) Everyone, except Author
Everyone is permitted to copy, distribute, modify, merge, sell, publish,
sublicense or whatever they want with this software but at their OWN RISK.
Preamble
The author has absolutely no clue what the code in this project does.
It might just work or not, there is no third option.
GOOD LUCK WITH THAT PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION, AND MODIFICATION
0. You just DO WHATEVER YOU WANT TO as long as you NEVER LEAVE A
TRACE TO TRACK THE AUTHOR of the original product to blame for or hold
responsible.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
Good luck and Godspeed.

25
Pizza.cs Normal file
View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PizzaExpress_Client
{
internal class Pizza
{
public int Id { get; set; }
public string Nome { get; set; } = string.Empty;
public decimal Prezzo { get; set; }
public string Categoria { get; set; } = string.Empty;
public string Note { get; set; } = string.Empty;
public int Tavolo { get; set; }
public string Stato { get; set; } = string.Empty;
public override string ToString()
{
return $"{Id}) {Nome} - {Categoria} [{Stato}]";
}
}
}

62
UrlForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,62 @@
namespace PizzaExpress_Client
{
partial class UrlForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
urlTxt = new Label();
SuspendLayout();
//
// urlTxt
//
urlTxt.Dock = DockStyle.Fill;
urlTxt.Font = new Font("Arial", 20.25F, FontStyle.Bold, GraphicsUnit.Point, 0);
urlTxt.Location = new Point(0, 0);
urlTxt.Name = "urlTxt";
urlTxt.Size = new Size(416, 105);
urlTxt.TabIndex = 0;
urlTxt.Text = "https://pizzeriadegitto.andrestork.moe:10469";
urlTxt.TextAlign = ContentAlignment.MiddleCenter;
//
// UrlForm
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(416, 105);
Controls.Add(urlTxt);
FormBorderStyle = FormBorderStyle.SizableToolWindow;
Name = "UrlForm";
Text = "Server URL";
Load += UrlForm_Load;
ResumeLayout(false);
}
#endregion
private Label urlTxt;
}
}

27
UrlForm.cs Normal file
View File

@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace PizzaExpress_Client
{
public partial class UrlForm : Form
{
public UrlForm(string srvUrl)
{
InitializeComponent();
urlTxt.Text = srvUrl;
}
private void UrlForm_Load(object sender, EventArgs e)
{
}
}
}

120
UrlForm.resx Normal file
View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>