diff --git a/README.md b/README.md index 86a62b2..a9bca7d 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ Doing so isn't fatal (it's not a secret), but it is annoying for other contribut * A basic AppleScript dictionary has been added as a way to inspect and control playback programatically. * Files can be dropped onto the dock icon to import them. * Empty artists entries are deleted from the local library on deleting downloaded items. +* The album sort order is configurable. By default, it sorts from oldest to newest. * Move request handling into an off-thread queue. * The album selection view has been rewritten to avoid deprecated types. * Fix tracks not having a cover when imported. diff --git a/Submariner/SBAppDelegate.swift b/Submariner/SBAppDelegate.swift index 8565990..3d3afdf 100644 --- a/Submariner/SBAppDelegate.swift +++ b/Submariner/SBAppDelegate.swift @@ -43,7 +43,8 @@ fileprivate let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, catego "MaxCoverSize": NSNumber(value: 300), "scrobbleToServer": NSNumber(value: true), "deleteAfterPlay": NSNumber(value: false), - "SkipIncrement": NSNumber(value: 5.0) + "SkipIncrement": NSNumber(value: 5.0), + "albumSortOrder": "OldestFirst", ] UserDefaults.standard.register(defaults: defaults) diff --git a/Submariner/SBMusicController.m b/Submariner/SBMusicController.m index 912ddc7..a35831e 100644 --- a/Submariner/SBMusicController.m +++ b/Submariner/SBMusicController.m @@ -91,6 +91,7 @@ - (void)viewDidAppear { - (void)dealloc { + [[NSUserDefaults standardUserDefaults] removeObserver: self forKeyPath: @"albumSortOrder"]; [artistsController removeObserver:self forKeyPath:@"selectedObjects"]; [albumsController removeObserver:self forKeyPath:@"selectedObjects"]; [tracksController removeObserver:self forKeyPath:@"selectedObjects"]; @@ -125,6 +126,11 @@ - (void)loadView { forKeyPath:@"selectedObjects" options:NSKeyValueObservingOptionNew context:nil]; + + [[NSUserDefaults standardUserDefaults] addObserver: self + forKeyPath: @"albumSortOrder" + options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial + context: nil]; } @@ -147,6 +153,9 @@ - (void)observeValueForKeyPath:(NSString *)keyPath } else if (object == tracksController && [keyPath isEqualToString:@"selectedObjects"] && self.view.window != nil) { [[NSNotificationCenter defaultCenter] postNotificationName: @"SBTrackSelectionChanged" object: tracksController.selectedObjects]; + } else if (object == [NSUserDefaults standardUserDefaults] && [keyPath isEqualToString: @"albumSortOrder"]) { + albumSortDescriptor = [self sortDescriptorsForPreference]; + albumsController.sortDescriptors = albumSortDescriptor; } } diff --git a/Submariner/SBPreferencesController.swift b/Submariner/SBPreferencesController.swift index ef00a39..d19dcb4 100644 --- a/Submariner/SBPreferencesController.swift +++ b/Submariner/SBPreferencesController.swift @@ -158,6 +158,7 @@ class SBPreferencesController: NSWindowController { struct AppearanceView: View { @AppStorage("coverSize") var coverSize = 0.75 + @AppStorage("albumSortOrder") var albumSortOrder = "OldestFirst" var body: some View { Form { @@ -173,6 +174,12 @@ class SBPreferencesController: NSWindowController { // the default minimum intrinsic width for a slider is paltry .frame(minWidth: 300) } + Section { + Picker(selection: $albumSortOrder, label: Text("Album sort order")) { + Text("Alphabetical").tag("Alphabetical") + Text("Oldest to newest").tag("OldestFirst") + } + } } .fixedSize() .padding(14) diff --git a/Submariner/SBServerHomeController.m b/Submariner/SBServerHomeController.m index 173f97c..ede3924 100644 --- a/Submariner/SBServerHomeController.m +++ b/Submariner/SBServerHomeController.m @@ -97,6 +97,7 @@ - (id)initWithManagedObjectContext:(NSManagedObjectContext *)context { - (void)dealloc { + [[NSUserDefaults standardUserDefaults] removeObserver: self forKeyPath: @"albumSortOrder"]; [albumsController removeObserver:self forKeyPath:@"arrangedObjects"]; [tracksController removeObserver:self forKeyPath:@"selectedObjects"]; } @@ -168,6 +169,11 @@ - (void)loadView { forKeyPath:@"selectedObjects" options:NSKeyValueObservingOptionNew context:nil]; + + [[NSUserDefaults standardUserDefaults] addObserver: self + forKeyPath: @"albumSortOrder" + options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial + context: nil]; } @@ -361,6 +367,9 @@ - (void)observeValueForKeyPath:(NSString *)keyPath } else if (object == albumsController && [keyPath isEqualToString:@"arrangedObjects"]) { [albumsCollectionView reloadData]; [albumsCollectionView setSelectionIndexes: albumsController.selectionIndexes]; + } else if (object == [NSUserDefaults standardUserDefaults] && [keyPath isEqualToString: @"albumSortOrder"]) { + albumSortDescriptor = [self sortDescriptorsForPreference]; + albumsController.sortDescriptors = albumSortDescriptor; } } diff --git a/Submariner/SBServerLibraryController.m b/Submariner/SBServerLibraryController.m index 75bef65..fb28e1b 100644 --- a/Submariner/SBServerLibraryController.m +++ b/Submariner/SBServerLibraryController.m @@ -112,6 +112,7 @@ - (void)viewDidAppear { - (void)dealloc { // remove subsonic observers + [[NSUserDefaults standardUserDefaults] removeObserver: self forKeyPath: @"albumSortOrder"]; [[NSNotificationCenter defaultCenter] removeObserver:self name:@"SBSubsonicCoversUpdatedNotification" object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:@"SBSubsonicTracksUpdatedNotification" object:nil]; [albumsController removeObserver:self forKeyPath:@"arrangedObjects"]; @@ -153,6 +154,11 @@ - (void)loadView { forKeyPath:@"selectedObjects" options:NSKeyValueObservingOptionNew context:nil]; + + [[NSUserDefaults standardUserDefaults] addObserver: self + forKeyPath: @"albumSortOrder" + options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial + context: nil]; } @@ -173,6 +179,9 @@ - (void)observeValueForKeyPath:(NSString *)keyPath } else if (object == albumsController && [keyPath isEqualToString:@"arrangedObjects"]) { [albumsCollectionView reloadData]; [albumsCollectionView setSelectionIndexes: albumsController.selectionIndexes]; + } else if (object == [NSUserDefaults standardUserDefaults] && [keyPath isEqualToString: @"albumSortOrder"]) { + albumSortDescriptor = [self sortDescriptorsForPreference]; + albumsController.sortDescriptors = albumSortDescriptor; } } diff --git a/Submariner/SBViewController.h b/Submariner/SBViewController.h index d5bc83d..f62ab79 100644 --- a/Submariner/SBViewController.h +++ b/Submariner/SBViewController.h @@ -69,4 +69,6 @@ typedef NS_OPTIONS(NSInteger, SBSelectedRowStatus) { - (SBSelectedRowStatus) selectedRowStatus:(NSArray*)trackList selectedIndices:(NSIndexSet*)indexSet; - (SBSelectedRowStatus) selectedRowStatus:(NSArray*)trackList; +- (NSArray*) sortDescriptorsForPreference; + @end diff --git a/Submariner/SBViewController.m b/Submariner/SBViewController.m index 424258c..c7502e5 100644 --- a/Submariner/SBViewController.m +++ b/Submariner/SBViewController.m @@ -95,6 +95,21 @@ - (void)viewDidAppear { #pragma mark - #pragma mark Library View Helper Functions +- (NSArray*) sortDescriptorsForPreference: (NSString*)preference { + NSSortDescriptor *albumNameDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"itemName" ascending:YES]; + if ([preference isEqualToString: @"OldestFirst"]) { + NSSortDescriptor *albumYearDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"year" ascending:YES]; + return @[albumYearDescriptor, albumNameDescriptor]; + } else { + return @[albumNameDescriptor]; + } +} + +- (NSArray*) sortDescriptorsForPreference { + NSString *newOrderType = [[NSUserDefaults standardUserDefaults] stringForKey: @"albumSortOrder"]; + return [self sortDescriptorsForPreference: newOrderType]; +} + -(void)showTracksInFinder:(NSArray*)trackList selectedIndices:(NSIndexSet*)indexSet { NSArray *selectedTracks = [trackList objectsAtIndexes: indexSet];