Skip to content

Commit a2c541d

Browse files
CopilotJusterZhu
andcommitted
Refactor ExtensionViewModel: Add error handling, validation, and user feedback
Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com>
1 parent c3cf089 commit a2c541d

1 file changed

Lines changed: 78 additions & 22 deletions

File tree

src/ViewModels/ExtensionViewModel.cs

Lines changed: 78 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using GeneralUpdate.Tool.Avalonia.Common;
1010
using GeneralUpdate.Tool.Avalonia.Models;
1111
using Newtonsoft.Json;
12+
using Nlnet.Avalonia.Controls;
1213

1314
namespace GeneralUpdate.Tool.Avalonia.ViewModels;
1415

@@ -19,7 +20,7 @@ public class ExtensionViewModel : ObservableObject
1920

2021
private ExtensionConfigModel? _configModel;
2122
private AsyncRelayCommand? _generateCommand;
22-
private AsyncRelayCommand<string>? _selectFolderCommand;
23+
private AsyncRelayCommand<string?>? _selectFolderCommand;
2324
private RelayCommand? _loadedCommand;
2425
private RelayCommand? _clearCommand;
2526
private AsyncRelayCommand? _selectDependenciesCommand;
@@ -38,9 +39,9 @@ public RelayCommand LoadedCommand
3839
get { return _loadedCommand ??= new RelayCommand(LoadedAction); }
3940
}
4041

41-
public AsyncRelayCommand<string> SelectFolderCommand
42+
public AsyncRelayCommand<string?> SelectFolderCommand
4243
{
43-
get => _selectFolderCommand ??= new AsyncRelayCommand<string>(SelectFolderAction);
44+
get => _selectFolderCommand ??= new AsyncRelayCommand<string?>(SelectFolderAction);
4445
}
4546

4647
public AsyncRelayCommand GenerateCommand
@@ -91,7 +92,10 @@ public string? NewCustomPropertyKey
9192
get => _newCustomPropertyKey;
9293
set
9394
{
94-
SetProperty(ref _newCustomPropertyKey, value);
95+
if (SetProperty(ref _newCustomPropertyKey, value))
96+
{
97+
AddCustomPropertyCommand.NotifyCanExecuteChanged();
98+
}
9599
}
96100
}
97101

@@ -100,7 +104,10 @@ public string? NewCustomPropertyValue
100104
get => _newCustomPropertyValue;
101105
set
102106
{
103-
SetProperty(ref _newCustomPropertyValue, value);
107+
if (SetProperty(ref _newCustomPropertyValue, value))
108+
{
109+
AddCustomPropertyCommand.NotifyCanExecuteChanged();
110+
}
104111
}
105112
}
106113

@@ -159,26 +166,42 @@ private void ResetAction()
159166
NewCustomPropertyValue = string.Empty;
160167
}
161168

162-
private async Task SelectFolderAction(string value)
169+
private async Task SelectFolderAction(string? value)
163170
{
164171
try
165172
{
173+
if (string.IsNullOrWhiteSpace(value))
174+
{
175+
await MessageBox.ShowAsync("Invalid folder selection parameter", "Error", Buttons.OK);
176+
return;
177+
}
178+
166179
var folders = await Storage.Instance.SelectFolderDialog();
167180
if (!folders.Any()) return;
168181

169182
var folder = folders.First();
183+
if (folder?.Path?.LocalPath == null)
184+
{
185+
await MessageBox.ShowAsync("Selected folder path is invalid", "Error", Buttons.OK);
186+
return;
187+
}
188+
170189
switch (value)
171190
{
172191
case "ExtensionDirectory":
173-
ConfigModel.ExtensionDirectory = folder!.Path.LocalPath;
192+
ConfigModel.ExtensionDirectory = folder.Path.LocalPath;
174193
break;
175194
case "ExportPath":
176-
ConfigModel.Path = folder!.Path.LocalPath;
195+
ConfigModel.Path = folder.Path.LocalPath;
196+
break;
197+
default:
198+
await MessageBox.ShowAsync($"Unknown folder selection type: {value}", "Error", Buttons.OK);
177199
break;
178200
}
179201
}
180-
catch (Exception e)
202+
catch (Exception ex)
181203
{
204+
await MessageBox.ShowAsync($"Failed to select folder: {ex.Message}", "Error", Buttons.OK);
182205
}
183206
}
184207

@@ -192,26 +215,31 @@ private async Task GeneratePackageAction()
192215
// Validate input
193216
if (string.IsNullOrWhiteSpace(ConfigModel.Name))
194217
{
195-
//eventAggregator.PublishWarning("Extension name is required");
218+
await MessageBox.ShowAsync("Extension name is required", "Validation Error", Buttons.OK);
196219
return;
197220
}
198221

199222
if (string.IsNullOrWhiteSpace(ConfigModel.Version))
200223
{
201-
//eventAggregator.PublishWarning("Extension version is required");
224+
await MessageBox.ShowAsync("Extension version is required", "Validation Error", Buttons.OK);
225+
return;
226+
}
227+
228+
if (string.IsNullOrWhiteSpace(ConfigModel.ExtensionDirectory))
229+
{
230+
await MessageBox.ShowAsync("Extension directory is required", "Validation Error", Buttons.OK);
202231
return;
203232
}
204233

205-
if (string.IsNullOrWhiteSpace(ConfigModel.ExtensionDirectory) ||
206-
!Directory.Exists(ConfigModel.ExtensionDirectory))
234+
if (!Directory.Exists(ConfigModel.ExtensionDirectory))
207235
{
208-
//eventAggregator.PublishWarning("Extension directory is invalid");
236+
await MessageBox.ShowAsync($"Extension directory does not exist: {ConfigModel.ExtensionDirectory}", "Validation Error", Buttons.OK);
209237
return;
210238
}
211239

212240
if (string.IsNullOrWhiteSpace(ConfigModel.Path))
213241
{
214-
//eventAggregator.PublishWarning("Export path is required");
242+
await MessageBox.ShowAsync("Export path is required", "Validation Error", Buttons.OK);
215243
return;
216244
}
217245

@@ -232,8 +260,6 @@ private async Task GeneratePackageAction()
232260
var zipFileName = $"{sanitizedName}_{sanitizedVersion}.zip";
233261
var zipFilePath = Path.Combine(exportDirectory, zipFileName);
234262

235-
//eventAggregator.PublishSuccess("Starting extension compression...");
236-
237263
// Compress the extension directory into a zip file
238264
await ZipUtility.CompressDirectoryAsync(
239265
ConfigModel.ExtensionDirectory,
@@ -248,19 +274,32 @@ await ZipUtility.CompressDirectoryAsync(
248274
var platformValue = ConfigModel.Platform?.Value ?? 0;
249275
var targetPlatform = MapPlatformValue(platformValue);
250276
ConfigModel.Platform = new PlatformModel{ DisplayName = targetPlatform.ToString(), Value = platformValue };
277+
251278
// Get file info for the zip
252279
var fileInfo = new FileInfo(zipFilePath);
253280
ConfigModel.FileSize = fileInfo.Length;
281+
254282
// Serialize manifest to JSON
255-
var manifestJson = JsonConvert.SerializeObject(ConfigModel);
283+
var manifestJson = JsonConvert.SerializeObject(ConfigModel, Formatting.Indented);
256284
if (!string.IsNullOrEmpty(manifestJson))
257285
{
258286
// Add manifest.json to the zip file
259287
await ZipUtility.AddFileToZipAsync(zipFilePath, "manifest.json", manifestJson);
260288
}
289+
290+
await MessageBox.ShowAsync($"Extension package created successfully at:\n{zipFilePath}", "Success", Buttons.OK);
291+
}
292+
catch (UnauthorizedAccessException ex)
293+
{
294+
await MessageBox.ShowAsync($"Access denied: {ex.Message}\nPlease check file permissions.", "Error", Buttons.OK);
295+
}
296+
catch (IOException ex)
297+
{
298+
await MessageBox.ShowAsync($"I/O error: {ex.Message}", "Error", Buttons.OK);
261299
}
262300
catch (Exception ex)
263301
{
302+
await MessageBox.ShowAsync($"Failed to generate package: {ex.Message}", "Error", Buttons.OK);
264303
}
265304
}
266305

@@ -276,15 +315,22 @@ private void AddCustomPropertyAction()
276315
{
277316
try
278317
{
279-
if (string.IsNullOrWhiteSpace(NewCustomPropertyKey) ||
280-
string.IsNullOrWhiteSpace(NewCustomPropertyValue))
318+
if (string.IsNullOrWhiteSpace(NewCustomPropertyKey))
281319
{
320+
MessageBox.Show("Property key cannot be empty", "Validation Error", Buttons.OK);
321+
return;
322+
}
323+
324+
if (string.IsNullOrWhiteSpace(NewCustomPropertyValue))
325+
{
326+
MessageBox.Show("Property value cannot be empty", "Validation Error", Buttons.OK);
282327
return;
283328
}
284329

285330
// Check if key already exists
286331
if (ConfigModel.CustomProperties.ContainsKey(NewCustomPropertyKey))
287332
{
333+
MessageBox.Show($"Property key '{NewCustomPropertyKey}' already exists", "Validation Error", Buttons.OK);
288334
return;
289335
}
290336

@@ -302,9 +348,12 @@ private void AddCustomPropertyAction()
302348
NewCustomPropertyKey = string.Empty;
303349
NewCustomPropertyValue = string.Empty;
304350

351+
// Notify command to re-evaluate its CanExecute state
352+
AddCustomPropertyCommand.NotifyCanExecuteChanged();
305353
}
306354
catch (Exception ex)
307355
{
356+
MessageBox.Show($"Failed to add custom property: {ex.Message}", "Error", Buttons.OK);
308357
}
309358
}
310359

@@ -314,21 +363,28 @@ private void RemoveCustomPropertyAction(CustomPropertyModel? property)
314363
{
315364
if (property == null)
316365
{
366+
MessageBox.Show("No property selected to remove", "Validation Error", Buttons.OK);
367+
return;
368+
}
369+
370+
if (string.IsNullOrWhiteSpace(property.Key))
371+
{
372+
MessageBox.Show("Property key is invalid", "Validation Error", Buttons.OK);
317373
return;
318374
}
319375

320-
// Remove from dictionary - use TryGetValue for safety
376+
// Remove from dictionary
321377
if (ConfigModel.CustomProperties.ContainsKey(property.Key))
322378
{
323379
ConfigModel.CustomProperties.Remove(property.Key);
324380
}
325381

326382
// Remove from observable collection
327383
CustomPropertiesCollection.Remove(property);
328-
329384
}
330385
catch (Exception ex)
331386
{
387+
MessageBox.Show($"Failed to remove custom property: {ex.Message}", "Error", Buttons.OK);
332388
}
333389
}
334390

0 commit comments

Comments
 (0)