using Sunfish.Host;
using Sunfish.Log;
using Sunfish.Net;
namespace Sunfish.WinForms;
/// <summary>
/// Ventana de informacion (boton "i", como en la 2.0): direcciones de cada share por interfaz
/// (doble clic las abre, menu para copiarlas), el registro y el "acerca de".
/// </summary>
internal sealed class InfoForm : Form
{
private readonly SunfishHost _host;
private readonly ListBox _addresses = new() { IntegralHeight = false, HorizontalScrollbar = true, Dock = DockStyle.Fill };
private readonly ListBox _log = new() { IntegralHeight = false, HorizontalScrollbar = true, Dock = DockStyle.Fill };
private readonly LinkLabel _adminLink = new() { AutoSize = true };
private readonly Action<LogEntry> _onLog;
private readonly Action _onChange;
public InfoForm(SunfishHost host)
{
_host = host;
SuspendLayout();
AutoScaleDimensions = new SizeF(96F, 96F);
AutoScaleMode = AutoScaleMode.Dpi;
Text = "Sunfish";
ClientSize = new Size(360, 420);
MinimumSize = new Size(300, 300);
StartPosition = FormStartPosition.CenterParent;
ShowInTaskbar = false;
MinimizeBox = false;
Padding = new Padding(6);
using (var stream = typeof(InfoForm).Assembly.GetManifestResourceStream("ui/logo.png"))
{
var header = new Panel { Dock = DockStyle.Top, Height = 56 };
if (stream is not null)
header.Controls.Add(new PictureBox { Image = Image.FromStream(stream), SizeMode = PictureBoxSizeMode.Zoom, Bounds = new Rectangle(0, 2, 48, 48) });
header.Controls.Add(new Label { Text = Texts.About, AutoSize = true, Location = new Point(56, 8) });
_adminLink.Location = new Point(56, 30);
_adminLink.LinkClicked += async (_, _) => await EditAdminAsync();
header.Controls.Add(_adminLink);
Controls.Add(header);
}
var addressesBox = new GroupBox { Text = Strings.AppAddresses, Dock = DockStyle.Fill, Padding = new Padding(4) };
addressesBox.Controls.Add(_addresses);
var logBox = new GroupBox { Text = Strings.AppLog, Dock = DockStyle.Fill, Padding = new Padding(4) };
logBox.Controls.Add(_log);
var split = new SplitContainer { Dock = DockStyle.Fill, Orientation = Orientation.Horizontal, SplitterDistance = 150 };
split.Panel1.Controls.Add(addressesBox);
split.Panel2.Controls.Add(logBox);
Controls.Add(split);
split.BringToFront();
ResumeLayout(false);
PerformLayout();
var menu = new ContextMenuStrip();
menu.Items.Add(Texts.OpenInBrowser, UiImages.Get("share"), (_, _) => MainForm.Open(SelectedUrl()));
menu.Items.Add(Texts.CopyUrl, null, (_, _) =>
{
if (SelectedUrl() is { } url)
Clipboard.SetText(url);
});
menu.Items.Add(Texts.ShowQr, null, (_, _) =>
{
if (SelectedUrl() is { } url)
UiPlacement.ShowCentered(new QrForm(url) { Icon = Icon }, this);
});
_addresses.ContextMenuStrip = menu;
_addresses.DoubleClick += (_, _) => MainForm.Open(SelectedUrl());
_onLog = entry => SafeInvoke(() => AddLog(entry));
_onChange = () => SafeInvoke(FillAddresses);
_host.Log.Written += _onLog;
_host.Changed += _onChange;
foreach (var entry in _host.Log.Recent())
AddLog(entry);
FillAddresses();
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
_host.Log.Written -= _onLog;
_host.Changed -= _onChange;
base.OnFormClosed(e);
}
private string? SelectedUrl()
{
if (_addresses.SelectedItem is not string text)
return null;
int space = text.IndexOf(' ');
bool url = text.StartsWith("http", StringComparison.Ordinal) || text.StartsWith("ftp", StringComparison.Ordinal);
return url ? (space < 0 ? text : text[..space]) : null;
}
private async Task EditAdminAsync()
{
var copy = _host.Config.Clone();
using var dialog = new AdminDialog(copy.Admin, _host.HttpPort);
if (dialog.ShowDialog(this) == DialogResult.OK)
await (copy.FilePath is null ? _host.ApplyAsync(copy) : _host.SaveAndApplyAsync(copy));
}
private void FillAddresses()
{
_adminLink.Text = Texts.AdminLink(_host.Config.Admin.Enabled && _host.Config.Admin.PasswordHash.Length > 0);
_addresses.Items.Clear();
if (!_host.HttpRunning && !_host.FtpRunning)
{
_addresses.Items.Add(Strings.AppStopped);
return;
}
var addresses = LocalAddresses.Get();
if (addresses.Count == 0)
_addresses.Items.Add(Texts.NoAddress);
foreach (var share in _host.Config.Shares.Where(s => s.Enabled))
{
_addresses.Items.Add($"[{share.Name}]");
foreach (var address in addresses)
{
if (_host.HttpRunning)
_addresses.Items.Add($"{LocalAddresses.HttpUrl(address.Address, _host.HttpPort, share)} ({address.Interface})");
if (_host.FtpRunning && share.Ftp)
_addresses.Items.Add($"{LocalAddresses.FtpUrl(address.Address, _host.FtpPort, share)} ({address.Interface})");
}
}
}
private void AddLog(LogEntry entry)
{
_log.Items.Add($"{entry.Time:HH:mm:ss} {entry.Message}");
while (_log.Items.Count > 1000)
_log.Items.RemoveAt(0);
_log.TopIndex = Math.Max(0, _log.Items.Count - 1);
}
private void SafeInvoke(Action action)
{
if (IsDisposed || !IsHandleCreated)
return;
try
{
BeginInvoke(action);
}
catch (InvalidOperationException) { }
}
}