added scroll reset and tab persistance
This commit is contained in:
@@ -20,4 +20,13 @@ public sealed class AppSettings
|
|||||||
/// costs noticeably more CPU and memory than showing static first frames.
|
/// costs noticeably more CPU and memory than showing static first frames.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool PlayGifPreviews { get; set; }
|
public bool PlayGifPreviews { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Which tab the picker reopens on. Persisted so the choice survives an app restart, not
|
||||||
|
/// just a hide/show. Defaults to the favourites view, since that is where the memes you
|
||||||
|
/// actually reach for most often live.
|
||||||
|
/// </summary>
|
||||||
|
public MemeSource LastSource { get; set; } = MemeSource.Local;
|
||||||
|
|
||||||
|
public bool LastShowingFavorites { get; set; } = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,7 +99,16 @@ public partial class PickerViewModel : ObservableObject
|
|||||||
_providers = providers.ToList();
|
_providers = providers.ToList();
|
||||||
|
|
||||||
Items.CollectionChanged += OnItemsChanged;
|
Items.CollectionChanged += OnItemsChanged;
|
||||||
RefreshLocalItems();
|
|
||||||
|
// Restore the tab the picker was last left on. Assigned to the backing fields directly
|
||||||
|
// so restoring doesn't count as a user change and immediately re-save.
|
||||||
|
_activeSource = _settings.Current.LastSource;
|
||||||
|
_showingFavorites = _settings.Current.LastShowingFavorites;
|
||||||
|
|
||||||
|
// Seed the grid for the restored view. Remote sources are skipped here because that
|
||||||
|
// needs an async call - OnShown covers it when the window is actually opened.
|
||||||
|
if (_showingFavorites) RefreshFavoriteItems();
|
||||||
|
else if (IsLocalSource) RefreshLocalItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnItemsChanged(object? sender, NotifyCollectionChangedEventArgs e) =>
|
private void OnItemsChanged(object? sender, NotifyCollectionChangedEventArgs e) =>
|
||||||
@@ -116,6 +125,7 @@ public partial class PickerViewModel : ObservableObject
|
|||||||
OnPropertyChanged(nameof(EmptyStateText));
|
OnPropertyChanged(nameof(EmptyStateText));
|
||||||
OnPropertyChanged(nameof(ShowEmptyState));
|
OnPropertyChanged(nameof(ShowEmptyState));
|
||||||
SearchText = string.Empty;
|
SearchText = string.Empty;
|
||||||
|
PersistViewState();
|
||||||
_ = RefreshAsync();
|
_ = RefreshAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,11 +137,19 @@ public partial class PickerViewModel : ObservableObject
|
|||||||
OnPropertyChanged(nameof(CanImport));
|
OnPropertyChanged(nameof(CanImport));
|
||||||
OnPropertyChanged(nameof(ShowEmptyState));
|
OnPropertyChanged(nameof(ShowEmptyState));
|
||||||
SearchText = string.Empty;
|
SearchText = string.Empty;
|
||||||
|
PersistViewState();
|
||||||
// Setting SearchText above only triggers a refresh if the value actually changed, so
|
// Setting SearchText above only triggers a refresh if the value actually changed, so
|
||||||
// refresh explicitly here to cover switching tabs with an already-empty box.
|
// refresh explicitly here to cover switching tabs with an already-empty box.
|
||||||
_ = RefreshAsync();
|
_ = RefreshAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void PersistViewState()
|
||||||
|
{
|
||||||
|
_settings.Current.LastSource = ActiveSource;
|
||||||
|
_settings.Current.LastShowingFavorites = ShowingFavorites;
|
||||||
|
_ = _settings.SaveAsync();
|
||||||
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void SelectSource(MemeSource source) => ActiveSource = source;
|
private void SelectSource(MemeSource source) => ActiveSource = source;
|
||||||
|
|
||||||
|
|||||||
@@ -202,7 +202,8 @@
|
|||||||
ToolTip="Add memes"/>
|
ToolTip="Add memes"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<ScrollViewer Grid.Row="3" VerticalScrollBarVisibility="Auto" Padding="0,0,4,0"
|
<ScrollViewer x:Name="ResultsScrollViewer"
|
||||||
|
Grid.Row="3" VerticalScrollBarVisibility="Auto" Padding="0,0,4,0"
|
||||||
ScrollChanged="ResultsScrollViewer_OnScrollChanged">
|
ScrollChanged="ResultsScrollViewer_OnScrollChanged">
|
||||||
<Grid>
|
<Grid>
|
||||||
<TextBlock Text="{Binding EmptyStateText}"
|
<TextBlock Text="{Binding EmptyStateText}"
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ public partial class PickerWindow : Window
|
|||||||
_autoPaste.CaptureForegroundWindow();
|
_autoPaste.CaptureForegroundWindow();
|
||||||
PositionNearCursor();
|
PositionNearCursor();
|
||||||
_viewModel.OnShown();
|
_viewModel.OnShown();
|
||||||
|
// Always reopen at the top rather than wherever the last session was left scrolled to.
|
||||||
|
ResultsScrollViewer.ScrollToTop();
|
||||||
Show();
|
Show();
|
||||||
Activate();
|
Activate();
|
||||||
SearchBox.Focus();
|
SearchBox.Focus();
|
||||||
@@ -88,6 +90,15 @@ public partial class PickerWindow : Window
|
|||||||
{
|
{
|
||||||
Activate();
|
Activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Switching tab/view or typing replaces the whole grid, so a retained scroll offset
|
||||||
|
// would leave the user part-way down a completely different set of results.
|
||||||
|
if (e.PropertyName is nameof(PickerViewModel.ActiveSource)
|
||||||
|
or nameof(PickerViewModel.ShowingFavorites)
|
||||||
|
or nameof(PickerViewModel.SearchText))
|
||||||
|
{
|
||||||
|
ResultsScrollViewer.ScrollToTop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PickerWindow_OnDeactivated(object? sender, EventArgs e)
|
private void PickerWindow_OnDeactivated(object? sender, EventArgs e)
|
||||||
|
|||||||
Reference in New Issue
Block a user