11using System ;
2+ using System . Collections . Generic ;
3+ using System . Linq ;
24
35using Avalonia ;
46using Avalonia . Controls ;
@@ -17,9 +19,196 @@ public Repository()
1719 protected override void OnLoaded ( RoutedEventArgs e )
1820 {
1921 base . OnLoaded ( e ) ;
22+ ApplySidebarViewOrder ( ) ;
23+ SyncViewSwitcherSelection ( ) ;
2024 UpdateLeftSidebarLayout ( ) ;
25+
26+ if ( DataContext is ViewModels . Repository repo )
27+ repo . PropertyChanged += OnRepositoryPropertyChanged ;
2128 }
2229
30+ protected override void OnUnloaded ( RoutedEventArgs e )
31+ {
32+ base . OnUnloaded ( e ) ;
33+
34+ if ( DataContext is ViewModels . Repository repo )
35+ repo . PropertyChanged -= OnRepositoryPropertyChanged ;
36+ }
37+
38+ private void OnRepositoryPropertyChanged ( object sender , System . ComponentModel . PropertyChangedEventArgs e )
39+ {
40+ if ( e . PropertyName == nameof ( ViewModels . Repository . SelectedViewIndex ) )
41+ SyncViewSwitcherSelection ( ) ;
42+ }
43+
44+ #region View Switcher Drag-Drop Reorder
45+
46+ private static readonly DataFormat < string > _dndViewSwitcherFormat =
47+ DataFormat . CreateStringApplicationFormat ( "sourcegit-dnd-view-switcher" ) ;
48+
49+ private bool _pressedViewItem = false ;
50+ private bool _startDragViewItem = false ;
51+ private Point _pressedViewItemPosition ;
52+
53+ private void ApplySidebarViewOrder ( )
54+ {
55+ var layout = ViewModels . Preferences . Instance . Layout ;
56+ var order = layout . SidebarViewOrder ;
57+ if ( order == null || order . Count != 3 )
58+ return ;
59+
60+ // Collect items by their Tag
61+ var itemsByTag = new Dictionary < int , ListBoxItem > ( ) ;
62+ foreach ( var obj in ViewSwitcher . Items )
63+ {
64+ if ( obj is ListBoxItem item && item . Tag is string tagStr && int . TryParse ( tagStr , out var tag ) )
65+ itemsByTag [ tag ] = item ;
66+ }
67+
68+ if ( itemsByTag . Count != 3 )
69+ return ;
70+
71+ // Reorder
72+ ViewSwitcher . Items . Clear ( ) ;
73+ foreach ( var tag in order )
74+ {
75+ if ( itemsByTag . TryGetValue ( tag , out var item ) )
76+ ViewSwitcher . Items . Add ( item ) ;
77+ }
78+ }
79+
80+ private void SyncViewSwitcherSelection ( )
81+ {
82+ if ( DataContext is not ViewModels . Repository repo )
83+ return ;
84+
85+ // Find the ListBoxItem whose Tag matches the current SelectedViewIndex
86+ foreach ( var obj in ViewSwitcher . Items )
87+ {
88+ if ( obj is ListBoxItem item && item . Tag is string tagStr &&
89+ int . TryParse ( tagStr , out var tag ) && tag == repo . SelectedViewIndex )
90+ {
91+ _suppressSelectionChanged = true ;
92+ ViewSwitcher . SelectedItem = item ;
93+ _suppressSelectionChanged = false ;
94+ break ;
95+ }
96+ }
97+ }
98+
99+ private bool _suppressSelectionChanged = false ;
100+
101+ private void OnViewSwitcherSelectionChanged ( object sender , SelectionChangedEventArgs e )
102+ {
103+ if ( _suppressSelectionChanged )
104+ return ;
105+
106+ if ( DataContext is ViewModels . Repository repo &&
107+ ViewSwitcher . SelectedItem is ListBoxItem item &&
108+ item . Tag is string tagStr &&
109+ int . TryParse ( tagStr , out var viewIndex ) )
110+ {
111+ repo . SelectedViewIndex = viewIndex ;
112+ }
113+ }
114+
115+ private static ListBoxItem FindParentListBoxItem ( Control control )
116+ {
117+ var parent = control . Parent ;
118+ while ( parent != null )
119+ {
120+ if ( parent is ListBoxItem item )
121+ return item ;
122+ parent = ( parent as Control ) ? . Parent ;
123+ }
124+ return null ;
125+ }
126+
127+ private void OnViewSwitcherItemPointerPressed ( object sender , PointerPressedEventArgs e )
128+ {
129+ if ( sender is Border border )
130+ {
131+ _pressedViewItem = true ;
132+ _startDragViewItem = false ;
133+ _pressedViewItemPosition = e . GetPosition ( border ) ;
134+ e . Handled = true ;
135+ }
136+ }
137+
138+ private void OnViewSwitcherItemPointerReleased ( object sender , PointerReleasedEventArgs e )
139+ {
140+ _pressedViewItem = false ;
141+ _startDragViewItem = false ;
142+ }
143+
144+ private async void OnViewSwitcherItemPointerMoved ( object sender , PointerEventArgs e )
145+ {
146+ if ( ! _pressedViewItem || _startDragViewItem || sender is not Border border )
147+ return ;
148+
149+ var delta = e . GetPosition ( border ) - _pressedViewItemPosition ;
150+ var sizeSquared = delta . X * delta . X + delta . Y * delta . Y ;
151+ if ( sizeSquared < 64 )
152+ return ;
153+
154+ _startDragViewItem = true ;
155+
156+ var listBoxItem = FindParentListBoxItem ( border ) ;
157+ if ( listBoxItem == null )
158+ return ;
159+
160+ var tag = listBoxItem . Tag as string ?? "" ;
161+ var data = new DataTransfer ( ) ;
162+ data . Add ( DataTransferItem . Create ( _dndViewSwitcherFormat , tag ) ) ;
163+ await DragDrop . DoDragDropAsync ( e , data , DragDropEffects . Move ) ;
164+ }
165+
166+ private void OnViewSwitcherItemDrop ( object sender , DragEventArgs e )
167+ {
168+ if ( e . DataTransfer . TryGetValue ( _dndViewSwitcherFormat ) is not { Length : > 0 } sourceTag )
169+ return ;
170+
171+ if ( sender is not ListBoxItem targetItem || targetItem . Tag is not string targetTag )
172+ return ;
173+
174+ if ( sourceTag == targetTag )
175+ return ;
176+
177+ // Find source and target indices in current Items list
178+ var items = ViewSwitcher . Items . Cast < ListBoxItem > ( ) . ToList ( ) ;
179+ var sourceIdx = items . FindIndex ( i => ( i . Tag as string ) == sourceTag ) ;
180+ var targetIdx = items . FindIndex ( i => ( i . Tag as string ) == targetTag ) ;
181+
182+ if ( sourceIdx < 0 || targetIdx < 0 )
183+ return ;
184+
185+ // Swap
186+ var sourceItem = items [ sourceIdx ] ;
187+ items . RemoveAt ( sourceIdx ) ;
188+ items . Insert ( targetIdx , sourceItem ) ;
189+
190+ // Rebuild ListBox
191+ _suppressSelectionChanged = true ;
192+ var selectedItem = ViewSwitcher . SelectedItem ;
193+ ViewSwitcher . Items . Clear ( ) ;
194+ foreach ( var item in items )
195+ ViewSwitcher . Items . Add ( item ) ;
196+ ViewSwitcher . SelectedItem = selectedItem ;
197+ _suppressSelectionChanged = false ;
198+
199+ // Persist order
200+ var newOrder = items . Select ( i => int . Parse ( i . Tag as string ?? "0" ) ) . ToList ( ) ;
201+ var layout = ViewModels . Preferences . Instance . Layout ;
202+ layout . SidebarViewOrder = newOrder ;
203+ ViewModels . Preferences . Instance . Save ( ) ;
204+
205+ _pressedViewItem = false ;
206+ _startDragViewItem = false ;
207+ e . Handled = true ;
208+ }
209+
210+ #endregion
211+
23212 private void OnSearchCommitPanelPropertyChanged ( object sender , AvaloniaPropertyChangedEventArgs e )
24213 {
25214 if ( e . Property == IsVisibleProperty && sender is Grid { IsVisible : true } )
0 commit comments