feat(ui): complete Avalonia UI port with 7 main pages, tool settings & top MenuBar

This commit is contained in:
Richard
2026-08-10 10:48:34 +02:00
parent a0e18d2a57
commit b5bf97ae74
187 changed files with 20054 additions and 882 deletions
@@ -0,0 +1,221 @@
using ClawdDotNet.Models;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace ClawdDotNet.Desktop.ViewModels;
public sealed partial class ToolSettingsViewModel : ViewModelBase
{
public string ToolName { get; }
public object? SettingsObject { get; }
// FTP
[ObservableProperty] private string _ftpHost = "";
[ObservableProperty] private int _ftpPort = 21;
[ObservableProperty] private string _ftpUsername = "";
[ObservableProperty] private string _ftpPassword = "";
[ObservableProperty] private string _ftpRootPath = "./data/";
// Mail
[ObservableProperty] private string _mailUsername = "";
[ObservableProperty] private string _mailPassword = "";
[ObservableProperty] private string _mailImapHost = "";
[ObservableProperty] private int _mailImapPort = 993;
[ObservableProperty] private string _mailSmtpHost = "";
[ObservableProperty] private int _mailSmtpPort = 587;
[ObservableProperty] private string _mailAllowedRecipients = "";
// Database
[ObservableProperty] private DatabaseType _dbType = DatabaseType.MySql;
[ObservableProperty] private string _dbConnectionString = "";
[ObservableProperty] private DatabaseAccessLevel _dbAccessLevel = DatabaseAccessLevel.ReadOnly;
[ObservableProperty] private string _dbAllowedTables = "";
// Telegram
[ObservableProperty] private string _telegramBotToken = "";
[ObservableProperty] private string _telegramDefaultChatId = "";
[ObservableProperty] private string _telegramAllowedChatIds = "";
// DirectAPI
[ObservableProperty] private string _directApiDefaultProvider = "twelvedata";
[ObservableProperty] private int _directApiCacheTtlSeconds = 60;
[ObservableProperty] private string _directApiTwelveDataKey = "";
[ObservableProperty] private string _directApiAlphaVantageKey = "";
// WebFetch
[ObservableProperty] private string _webFetchAllowedDomains = "";
[ObservableProperty] private int _webFetchMaxResponseKb = 512;
[ObservableProperty] private string _webFetchUserAgent = "ClawdDotNet-Agent/1.0";
// SocialMediaManager
[ObservableProperty] private string _smmXApiKey = "";
[ObservableProperty] private string _smmXWatchAccounts = "";
[ObservableProperty] private string _smmRedditWatchSubreddits = "";
[ObservableProperty] private int _smmRedditPostLimit = 15;
[ObservableProperty] private string _smmOpenRouterApiKey = "";
[ObservableProperty] private string _smmSttModel = "openai/whisper-1";
[ObservableProperty] private string _smmYoutubeChannels = "";
// FileRW
[ObservableProperty] private string _fileRwPersonalAllowedExtensions = ".txt,.json,.md,.html,.js,.css";
[ObservableProperty] private FileRWAccessLevel _fileRwSharedAccessLevel = FileRWAccessLevel.Denied;
[ObservableProperty] private string _fileRwSharedAllowedExtensions = ".txt,.json,.md";
[ObservableProperty] private string _fileRwProtectedPaths = "stocks/";
public List<DatabaseType> DbTypes { get; } = [DatabaseType.MySql, DatabaseType.Postgres, DatabaseType.MsSql, DatabaseType.MongoDb];
public List<DatabaseAccessLevel> DbAccessLevels { get; } = [DatabaseAccessLevel.ReadOnly, DatabaseAccessLevel.ReadWrite, DatabaseAccessLevel.Admin];
public List<FileRWAccessLevel> FileRwAccessLevels { get; } = [FileRWAccessLevel.Denied, FileRWAccessLevel.Read, FileRWAccessLevel.ReadWrite, FileRWAccessLevel.Admin];
public Dictionary<string, object?>? Result { get; private set; }
public event Action? CloseRequested;
public ToolSettingsViewModel() : this("FTP", new()) { }
public ToolSettingsViewModel(string toolName, Dictionary<string, object?> config)
{
ToolName = toolName;
SettingsObject = ToolSettingsFactory.CreateViewModel(toolName, config);
switch (SettingsObject)
{
case FTPToolSettings ftp:
FtpHost = ftp.Host;
FtpPort = ftp.Port;
FtpUsername = ftp.Username;
FtpPassword = ftp.Password;
FtpRootPath = ftp.RootPath;
break;
case MailToolSettings mail:
MailUsername = mail.Username;
MailPassword = mail.Password;
MailImapHost = mail.ImapHost;
MailImapPort = mail.ImapPort;
MailSmtpHost = mail.SmtpHost;
MailSmtpPort = mail.SmtpPort;
MailAllowedRecipients = mail.AllowedRecipients;
break;
case DatabaseToolSettings db:
DbType = db.Type;
DbConnectionString = db.ConnectionString;
DbAccessLevel = db.AccessLevel;
DbAllowedTables = db.AllowedTables;
break;
case TelegramToolSettings tg:
TelegramBotToken = tg.BotToken;
TelegramDefaultChatId = tg.DefaultChatId;
TelegramAllowedChatIds = tg.AllowedChatIds;
break;
case DirectAPIToolSettings dapi:
DirectApiDefaultProvider = dapi.DefaultProvider;
DirectApiCacheTtlSeconds = dapi.CacheTtlSeconds;
DirectApiTwelveDataKey = dapi.TwelveDataKey;
DirectApiAlphaVantageKey = dapi.AlphaVantageKey;
break;
case WebFetchToolSettings wf:
WebFetchAllowedDomains = wf.AllowedDomains;
WebFetchMaxResponseKb = wf.MaxResponseKb;
WebFetchUserAgent = wf.UserAgent;
break;
case SocialMediaManagerToolSettings smm:
SmmXApiKey = smm.XApiKey;
SmmXWatchAccounts = smm.XWatchAccounts;
SmmRedditWatchSubreddits = smm.RedditWatchSubreddits;
SmmRedditPostLimit = smm.RedditPostLimit;
SmmOpenRouterApiKey = smm.OpenRouterApiKey;
SmmSttModel = smm.STTModel;
SmmYoutubeChannels = smm.YoutubeChannels;
break;
case FileRWToolSettings frw:
FileRwPersonalAllowedExtensions = frw.PersonalAllowedExtensions;
FileRwSharedAccessLevel = frw.SharedAccessLevel;
FileRwSharedAllowedExtensions = frw.SharedAllowedExtensions;
FileRwProtectedPaths = frw.ProtectedPaths;
break;
}
}
[RelayCommand]
private void Confirm()
{
switch (SettingsObject)
{
case FTPToolSettings ftp:
ftp.Host = FtpHost;
ftp.Port = FtpPort;
ftp.Username = FtpUsername;
ftp.Password = FtpPassword;
ftp.RootPath = FtpRootPath;
break;
case MailToolSettings mail:
mail.Username = MailUsername;
mail.Password = MailPassword;
mail.ImapHost = MailImapHost;
mail.ImapPort = MailImapPort;
mail.SmtpHost = MailSmtpHost;
mail.SmtpPort = MailSmtpPort;
mail.AllowedRecipients = MailAllowedRecipients;
break;
case DatabaseToolSettings db:
db.Type = DbType;
db.ConnectionString = DbConnectionString;
db.AccessLevel = DbAccessLevel;
db.AllowedTables = DbAllowedTables;
break;
case TelegramToolSettings tg:
tg.BotToken = TelegramBotToken;
tg.DefaultChatId = TelegramDefaultChatId;
tg.AllowedChatIds = TelegramAllowedChatIds;
break;
case DirectAPIToolSettings dapi:
dapi.DefaultProvider = DirectApiDefaultProvider;
dapi.CacheTtlSeconds = DirectApiCacheTtlSeconds;
dapi.TwelveDataKey = DirectApiTwelveDataKey;
dapi.AlphaVantageKey = DirectApiAlphaVantageKey;
break;
case WebFetchToolSettings wf:
wf.AllowedDomains = WebFetchAllowedDomains;
wf.MaxResponseKb = WebFetchMaxResponseKb;
wf.UserAgent = WebFetchUserAgent;
break;
case SocialMediaManagerToolSettings smm:
smm.XApiKey = SmmXApiKey;
smm.XWatchAccounts = SmmXWatchAccounts;
smm.RedditWatchSubreddits = SmmRedditWatchSubreddits;
smm.RedditPostLimit = SmmRedditPostLimit;
smm.OpenRouterApiKey = SmmOpenRouterApiKey;
smm.STTModel = SmmSttModel;
smm.YoutubeChannels = SmmYoutubeChannels;
break;
case FileRWToolSettings frw:
frw.PersonalAllowedExtensions = FileRwPersonalAllowedExtensions;
frw.SharedAccessLevel = FileRwSharedAccessLevel;
frw.SharedAllowedExtensions = FileRwSharedAllowedExtensions;
frw.ProtectedPaths = FileRwProtectedPaths;
break;
}
Result = ToolSettingsFactory.ToConfig(ToolName, SettingsObject) ?? new();
CloseRequested?.Invoke();
}
[RelayCommand]
private void Cancel()
{
Result = null;
CloseRequested?.Invoke();
}
}