@@ -43,6 +43,11 @@ public SessionViewModel? ActiveSession
4343 }
4444 public bool HasMultipleSessions => Sessions . Count > 1 ;
4545
46+ /// <summary>Set by App.axaml.cs when user picks a history entry to restore.</summary>
47+ public SessionHistoryEntry ? PendingHistoryRestore { get ; set ; }
48+ /// <summary>Set by App.axaml.cs when user picks "Open Files" from the welcome screen.</summary>
49+ public bool PendingOpenFiles { get ; set ; }
50+
4651 // ── Split view ──
4752 [ ObservableProperty ] private SplitMode _splitMode = SplitMode . None ;
4853 [ ObservableProperty ] private SessionViewModel ? _secondaryPaneSession ;
@@ -351,7 +356,7 @@ private void LoadFromSession(SessionViewModel session)
351356 }
352357
353358 MapTileCount = MapData ? . Tiles . Count ?? 0 ;
354- Dispatcher . UIThread . Post ( RefreshFilteredTowns ) ;
359+ RefreshFilteredTowns ( ) ;
355360
356361 // Restore map viewport state
357362 MapCurrentFloor = session . MapCurrentFloor ;
@@ -3072,8 +3077,7 @@ private async Task LoadMapFromPath(string path)
30723077 MapStatusText = $ "Map loaded: { MapTileCount : N0} tiles, { MapData . Towns . Count } towns, { MapData . Spawns . Count } spawns, { MapData . Houses . Count } houses — { Path . GetFileName ( path ) } ";
30733078 MapHasUnsavedChanges = false ;
30743079 AddMapLog ( $ "Map opened: { Path . GetFileName ( path ) } ({ MapTileCount : N0} tiles)") ;
3075- // Defer town refresh so the Properties panel ListBox is realized first
3076- Dispatcher . UIThread . Post ( RefreshFilteredTowns ) ;
3080+ RefreshFilteredTowns ( ) ;
30773081 OnPropertyChanged ( nameof ( MapFloors ) ) ;
30783082 OnPropertyChanged ( nameof ( ExposedDatData ) ) ;
30793083 OnPropertyChanged ( nameof ( ExposedSprFile ) ) ;
@@ -4604,22 +4608,40 @@ private async Task LoadOtbFromPath(string path)
46044608
46054609 public async Task TryLoadLastSessionAsync ( )
46064610 {
4607- // Restore View menu toggles
4608- RestoreViewSettings ( ) ;
4611+ // If a history entry was selected from the welcome screen, restore it
4612+ if ( PendingHistoryRestore is { } entry )
4613+ {
4614+ PendingHistoryRestore = null ;
4615+ // Restore view settings from the history entry
4616+ RestoreViewSettings ( entry . ViewSettings ) ;
4617+ // Load sessions from the history entry
4618+ _appSettings . Sessions = new List < SavedSession > ( entry . Tabs ) ;
4619+ EnsureDefaultSession ( ) ;
4620+ if ( _appSettings . Sessions . Count > 0 )
4621+ await RestoreSessionsFromSettings ( ) ;
4622+ return ;
4623+ }
46094624
4610- EnsureDefaultSession ( ) ;
4625+ // If user chose "Open Files", just set up a blank session
4626+ if ( PendingOpenFiles )
4627+ {
4628+ PendingOpenFiles = false ;
4629+ RestoreViewSettings ( _appSettings . ViewSettings ) ;
4630+ EnsureDefaultSession ( ) ;
4631+ // The MainWindow.Loaded handler will trigger the Open Client dialog
4632+ return ;
4633+ }
46114634
4612- // Restore sessions from previous app run
4635+ // Default: restore view settings and sessions (backwards compat / no welcome)
4636+ RestoreViewSettings ( _appSettings . ViewSettings ) ;
4637+ EnsureDefaultSession ( ) ;
46134638 if ( _appSettings . Sessions . Count > 0 )
4614- {
46154639 await RestoreSessionsFromSettings ( ) ;
4616- }
46174640 }
46184641
4619- private void RestoreViewSettings ( )
4642+ private void RestoreViewSettings ( Dictionary < string , bool > ? vs )
46204643 {
4621- var vs = _appSettings . ViewSettings ;
4622- if ( vs . Count == 0 ) return ;
4644+ if ( vs == null || vs . Count == 0 ) return ;
46234645
46244646 if ( vs . TryGetValue ( nameof ( ViewShowAllFloors ) , out var v ) ) ViewShowAllFloors = v ;
46254647 if ( vs . TryGetValue ( nameof ( ViewShowAnimation ) , out v ) ) ViewShowAnimation = v ;
@@ -4649,10 +4671,10 @@ public void SaveSessionsToSettings()
46494671 if ( _currentSession != null )
46504672 SaveCurrentToSession ( _currentSession ) ;
46514673
4652- _appSettings . Sessions . Clear ( ) ;
4674+ var savedTabs = new List < SavedSession > ( ) ;
46534675 foreach ( var session in Sessions )
46544676 {
4655- _appSettings . Sessions . Add ( new SavedSession
4677+ savedTabs . Add ( new SavedSession
46564678 {
46574679 ClientFolderPath = session . ClientFolderPath ,
46584680 OtbPath = session . OtbPath ,
@@ -4666,8 +4688,10 @@ public void SaveSessionsToSettings()
46664688 } ) ;
46674689 }
46684690
4691+ _appSettings . Sessions = new List < SavedSession > ( savedTabs ) ;
4692+
46694693 // Persist View menu toggles
4670- _appSettings . ViewSettings = new Dictionary < string , bool >
4694+ var viewSettings = new Dictionary < string , bool >
46714695 {
46724696 [ nameof ( ViewShowAllFloors ) ] = ViewShowAllFloors ,
46734697 [ nameof ( ViewShowAnimation ) ] = ViewShowAnimation ,
@@ -4689,10 +4713,59 @@ public void SaveSessionsToSettings()
46894713 [ nameof ( ViewShowTooltips ) ] = ViewShowTooltips ,
46904714 [ nameof ( ViewShowIngameBox ) ] = ViewShowIngameBox ,
46914715 } ;
4716+ _appSettings . ViewSettings = viewSettings ;
4717+
4718+ // Add a history entry for this closing session (only if there's meaningful data)
4719+ if ( savedTabs . Any ( t => t . ClientFolderPath != null || t . OtbPath != null || t . MapFilePath != null ) )
4720+ {
4721+ var historyEntry = new SessionHistoryEntry
4722+ {
4723+ ClosedAt = DateTime . UtcNow ,
4724+ DisplayName = BuildHistoryDisplayName ( savedTabs ) ,
4725+ Tabs = new List < SavedSession > ( savedTabs ) ,
4726+ ViewSettings = new Dictionary < string , bool > ( viewSettings ) ,
4727+ } ;
4728+
4729+ // Remove duplicate entries (same set of file paths)
4730+ var key = string . Join ( "|" , savedTabs
4731+ . OrderBy ( t => t . ClientFolderPath )
4732+ . Select ( t => $ "{ t . ClientFolderPath } :{ t . OtbPath } :{ t . MapFilePath } ") ) ;
4733+ _appSettings . History . RemoveAll ( h =>
4734+ {
4735+ var hk = string . Join ( "|" , h . Tabs
4736+ . OrderBy ( t => t . ClientFolderPath )
4737+ . Select ( t => $ "{ t . ClientFolderPath } :{ t . OtbPath } :{ t . MapFilePath } ") ) ;
4738+ return hk == key ;
4739+ } ) ;
4740+
4741+ _appSettings . History . Insert ( 0 , historyEntry ) ;
4742+
4743+ // Keep only the 20 most recent
4744+ if ( _appSettings . History . Count > 20 )
4745+ _appSettings . History . RemoveRange ( 20 , _appSettings . History . Count - 20 ) ;
4746+ }
46924747
46934748 _appSettings . Save ( ) ;
46944749 }
46954750
4751+ private static string BuildHistoryDisplayName ( List < SavedSession > tabs )
4752+ {
4753+ var maps = tabs
4754+ . Where ( t => ! string . IsNullOrEmpty ( t . MapFilePath ) )
4755+ . Select ( t => Path . GetFileName ( t . MapFilePath ) )
4756+ . ToList ( ) ;
4757+ if ( maps . Count > 0 ) return string . Join ( ", " , maps . Take ( 3 ) ) ;
4758+
4759+ var protocols = tabs
4760+ . Where ( t => t . ProtocolVersion > 0 )
4761+ . Select ( t => $ "v{ t . ProtocolVersion } ")
4762+ . Distinct ( )
4763+ . ToList ( ) ;
4764+ if ( protocols . Count > 0 ) return string . Join ( ", " , protocols ) ;
4765+
4766+ return $ "{ tabs . Count } tab{ ( tabs . Count != 1 ? "s" : "" ) } ";
4767+ }
4768+
46964769 /// <summary>Restore sessions saved from a previous app run.</summary>
46974770 private async Task RestoreSessionsFromSettings ( )
46984771 {
@@ -4824,6 +4897,7 @@ private async Task LoadSessionFiles(SessionViewModel session)
48244897 MapCurrentFloor = session . MapCurrentFloor ;
48254898 MapZoom = session . MapZoom ;
48264899 OnPropertyChanged ( nameof ( MapFloors ) ) ;
4900+ RefreshFilteredTowns ( ) ;
48274901 }
48284902
48294903 StatusText = IsClientLoaded
0 commit comments