11using System . IO ;
22using System . Text . Json ;
33using System . Text . Json . Serialization ;
4- using CSharpCodeAnalyst . Features . Import ;
54using CSharpCodeAnalyst . Persistence . Contracts ;
65using CSharpCodeAnalyst . Persistence . Dto ;
7- using CSharpCodeAnalyst . Resources ;
86using CSharpCodeAnalyst . Shared ;
9- using CSharpCodeAnalyst . Shared . Notifications ;
107
118namespace CSharpCodeAnalyst . Persistence . Json ;
129
1310/// <summary>
1411/// JSON-file based implementation of <see cref="IProjectStorage" />.
12+ /// Pure I/O — no UI dependency, no file dialogs, no notifications, no events.
1513/// </summary>
1614public class JsonProjectStorage : IProjectStorage
1715{
18- private readonly IUserNotification _ui ;
1916 private ProjectData ? _snapshot ;
2017
21- public JsonProjectStorage ( IUserNotification ui )
22- {
23- _ui = ui ;
24- }
25-
2618 public bool HasSnapshot => _snapshot != null ;
2719
28- public event EventHandler < ImportStateChangedArgs > ? LoadingStateChanged ;
29-
30- /// <inheritdoc />
31- public async Task < Result < ( string fileName , ProjectData data ) > > LoadAsync ( )
32- {
33- var fileName = _ui . ShowOpenFileDialog ( "JSON files (*.json)|*.json" , "Load Project" ) ;
34- if ( string . IsNullOrEmpty ( fileName ) )
35- {
36- return Result < ( string , ProjectData ) > . Canceled ( ) ;
37- }
38-
39- return await LoadFromFileAsync ( fileName ) ;
40- }
41-
4220 /// <inheritdoc />
43- public async Task < Result < ( string fileName , ProjectData data ) > > LoadFromFileAsync ( string filePath )
21+ public async Task < Result < ProjectData > > LoadFromFileAsync ( string filePath )
4422 {
4523 try
4624 {
47- OnLoadingStateChanged ( "Loading..." , true ) ;
48-
4925 var projectData = await Task . Run ( ( ) => DeserializeProject ( filePath ) ) ;
50- return Result < ( string , ProjectData ) > . Success ( ( filePath , projectData ) ) ;
26+ return Result < ProjectData > . Success ( projectData ) ;
5127 }
5228 catch ( Exception ex )
5329 {
54- ShowError ( ex ) ;
55- return Result < ( string , ProjectData ) > . Failure ( ex ) ;
56- }
57- finally
58- {
59- OnLoadingStateChanged ( string . Empty , false ) ;
30+ return Result < ProjectData > . Failure ( ex ) ;
6031 }
6132 }
6233
6334 /// <inheritdoc />
64- public Result < string > Save ( ProjectData data , string ? currentFilePath = null )
35+ public Result SaveToFile ( ProjectData data , string filePath )
6536 {
66- if ( ! TryGetSaveFilePath ( currentFilePath , out var filePath ) )
67- {
68- return Result < string > . Canceled ( ) ;
69- }
70-
7137 try
7238 {
7339 SerializeProject ( data , filePath ) ;
74- return Result < string > . Success ( filePath ) ;
40+ return Result . Success ( ) ;
7541 }
7642 catch ( Exception ex )
7743 {
78- ShowError ( ex ) ;
79- return Result < string > . Failure ( ex ) ;
44+ return Result . Failure ( ex ) ;
8045 }
8146 }
8247
8348 /// <inheritdoc />
8449 public void CreateSnapshot ( ProjectData data )
8550 {
8651 _snapshot = data ;
87- _ui . ShowSuccess ( Strings . Snapshot_Success ) ;
8852 }
8953
9054 /// <inheritdoc />
91- public void RestoreSnapshot ( Action < ProjectData > restoreAction )
55+ public Result < ProjectData > RestoreSnapshot ( )
9256 {
93- if ( ! HasSnapshot )
57+ if ( _snapshot is null )
9458 {
95- _ui . ShowWarning ( Strings . Restore_NoSnapshot ) ;
96- return ;
59+ return Result < ProjectData > . Failure ( new InvalidOperationException ( "No snapshot available." ) ) ;
9760 }
9861
99- try
100- {
101- OnLoadingStateChanged ( Strings . Restore_LoadMessage , true ) ;
102- restoreAction ( _snapshot ! ) ;
103- _ui . ShowSuccess ( Strings . Restore_Success ) ;
104- }
105- catch ( Exception ex )
106- {
107- ShowError ( ex ) ;
108- }
109- finally
110- {
111- OnLoadingStateChanged ( string . Empty , false ) ;
112- }
113- }
114-
115- private void OnLoadingStateChanged ( string message , bool isLoading )
116- {
117- LoadingStateChanged ? . Invoke ( this , new ImportStateChangedArgs ( message , isLoading ) ) ;
118- }
119-
120- private void ShowError ( Exception ex )
121- {
122- var message = string . Format ( Strings . OperationFailed_Message , ex . Message ) ;
123- _ui . ShowError ( message ) ;
62+ return Result < ProjectData > . Success ( _snapshot ) ;
12463 }
12564
12665 private static ProjectData DeserializeProject ( string filePath )
@@ -136,30 +75,8 @@ private static ProjectData DeserializeProject(string filePath)
13675
13776 private static void SerializeProject ( ProjectData projectData , string filePath )
13877 {
139- var options = new JsonSerializerOptions
140- {
141- WriteIndented = false
142- } ;
78+ var options = new JsonSerializerOptions { WriteIndented = false } ;
14379 var json = JsonSerializer . Serialize ( projectData , options ) ;
14480 File . WriteAllText ( filePath , json ) ;
14581 }
146-
147- private bool TryGetSaveFilePath ( string ? currentFilePath , out string outFileName )
148- {
149- if ( ! string . IsNullOrEmpty ( currentFilePath ) )
150- {
151- outFileName = currentFilePath ;
152- return true ;
153- }
154-
155- var fileName = _ui . ShowSaveFileDialog ( "JSON files (*.json)|*.json" , "Save Project" ) ;
156- if ( string . IsNullOrEmpty ( fileName ) )
157- {
158- outFileName = string . Empty ;
159- return false ;
160- }
161-
162- outFileName = fileName ;
163- return true ;
164- }
165- }
82+ }
0 commit comments