From b6d1c4ae985827a5b58d94a3fbd11928ea7cbdc4 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Wed, 15 May 2024 01:54:12 -0300 Subject: [PATCH] Finagle the sort order a little Navidrome at least has an [Unknown] index with an [Unknown Artist] artist entry below it, but the Foundation sorting puts it in a clumsy place with the index and artist flipped. Provide a custom sort order that deals with it. Ugly and Navidrome specific, but does work. I'm considering preserving the order the server gives us, but that has its own problems (is it actually desirable?). Might need to rethink the schema with index vs. artist a little. --- Submariner.xcodeproj/project.pbxproj | 4 +++ Submariner/NSString+Comparison.swift | 40 ++++++++++++++++++++++++++ Submariner/SBMusicController.m | 2 +- Submariner/SBServerLibraryController.m | 2 +- 4 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 Submariner/NSString+Comparison.swift diff --git a/Submariner.xcodeproj/project.pbxproj b/Submariner.xcodeproj/project.pbxproj index 23ba09b..80818c8 100644 --- a/Submariner.xcodeproj/project.pbxproj +++ b/Submariner.xcodeproj/project.pbxproj @@ -51,6 +51,7 @@ 3E70B2E12A2D52A1002C0B93 /* SBPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E70B2E02A2D52A1002C0B93 /* SBPlayer.swift */; }; 3E7491972B6A1AE00052CBCE /* SBTracklistController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E7491962B6A1AE00052CBCE /* SBTracklistController.swift */; }; 3E8124272BEFF4F80060DDAF /* SBToggleNameTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E8124262BEFF4F80060DDAF /* SBToggleNameTransformer.swift */; }; + 3E8124292BF408110060DDAF /* NSString+Comparison.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E8124282BF408110060DDAF /* NSString+Comparison.swift */; }; 3E82701827E653F0007E5695 /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3E82701727E653F0007E5695 /* MediaPlayer.framework */; }; 3E87E90E2B43557400E85000 /* SBServerSearchController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E87E90D2B43557400E85000 /* SBServerSearchController.swift */; }; 3E87E9102B4364CF00E85000 /* Collection+IndexSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E87E90F2B4364CF00E85000 /* Collection+IndexSet.swift */; }; @@ -209,6 +210,7 @@ 3E70B2E02A2D52A1002C0B93 /* SBPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SBPlayer.swift; sourceTree = ""; }; 3E7491962B6A1AE00052CBCE /* SBTracklistController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SBTracklistController.swift; sourceTree = ""; }; 3E8124262BEFF4F80060DDAF /* SBToggleNameTransformer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SBToggleNameTransformer.swift; sourceTree = ""; }; + 3E8124282BF408110060DDAF /* NSString+Comparison.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSString+Comparison.swift"; sourceTree = ""; }; 3E82701727E653F0007E5695 /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; }; 3E87E90D2B43557400E85000 /* SBServerSearchController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SBServerSearchController.swift; sourceTree = ""; }; 3E87E90F2B4364CF00E85000 /* Collection+IndexSet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Collection+IndexSet.swift"; sourceTree = ""; }; @@ -592,6 +594,7 @@ 4CFB3E05139CEA76008DC01A /* NSOutlineView+Expand.h */, 4CFB3E06139CEA76008DC01A /* NSOutlineView+Expand.m */, 3E32BE542B8E500500E77CF0 /* NSPasteboard+Library.swift */, + 3E8124282BF408110060DDAF /* NSString+Comparison.swift */, 3E2F86D728E8F5BD00C5CE23 /* NSTreeController+IndexPath.swift */, 3EC03AC229F33C68001FDE50 /* OperationQueue+Shared.swift */, 3E87E9112B436B4500E85000 /* PasteboardType+Submariner.swift */, @@ -876,6 +879,7 @@ 3EC039C929EFC259001FDE50 /* View+Modify.swift in Sources */, 3EC03B3A29F4F2E0001FDE50 /* SBAlbum.swift in Sources */, 3EB2BCD12992FD5A00DC5056 /* SBTracklistButton.swift in Sources */, + 3E8124292BF408110060DDAF /* NSString+Comparison.swift in Sources */, 4CFB3E14139D028D008DC01A /* SBSheetController.m in Sources */, 4CFB3E15139D028D008DC01A /* SBServerViewController.m in Sources */, 3E189E4028EF5BAB0062ACA0 /* SBAudioMetadata.swift in Sources */, diff --git a/Submariner/NSString+Comparison.swift b/Submariner/NSString+Comparison.swift new file mode 100644 index 0000000..69be12a --- /dev/null +++ b/Submariner/NSString+Comparison.swift @@ -0,0 +1,40 @@ +// +// NSString+Comparison.swift +// Submariner +// +// Created by Calvin Buckley on 2024-05-14. +// +// Copyright (c) 2024 Calvin Buckley +// SPDX-License-Identifier: BSD-3-Clause +// + +import Foundation + +extension NSString { + private func isUnknownValue(_ string: String) -> Bool { + return string.starts(with: "[Unknown") && string.last == "]" + } + + @objc func artistListCompare(_ rhs: String) -> ComparisonResult { + let lhs = self as String + // Our goal with this is to kick the special unknown values to the bottom. + // For example in Navidrome, there is the [Unknown] index group as well as + // [Unknown Artist] and [Unknown Album]. The default sorting behaviours from + // Foundation are unpleasant and put the group after the artist, or put them + // in the middle of the list. + // This is Navidrome specific unfortunately. + // In the future other comparison changes could be made. + let lhsUnknown = isUnknownValue(lhs) + let rhsUnknown = isUnknownValue(rhs) + if lhsUnknown && !rhsUnknown { + return .orderedDescending + } else if !lhsUnknown && rhsUnknown { + return .orderedAscending + } else if lhsUnknown && rhsUnknown { + // we won't see special items of the same length + return lhs.count < rhs.count ? .orderedAscending : .orderedDescending + } + + return self.caseInsensitiveCompare(rhs) + } +} diff --git a/Submariner/SBMusicController.m b/Submariner/SBMusicController.m index b16bc1a..ec3afe4 100644 --- a/Submariner/SBMusicController.m +++ b/Submariner/SBMusicController.m @@ -59,7 +59,7 @@ - (NSString*)title { - (id)initWithManagedObjectContext:(NSManagedObjectContext *)context { self = [super initWithManagedObjectContext:context]; if (self) { - NSSortDescriptor *artistDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"itemName" ascending:YES selector: @selector(caseInsensitiveCompare:)]; + NSSortDescriptor *artistDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"itemName" ascending:YES selector: @selector(artistListCompare:)]; artistSortDescriptor = [NSArray arrayWithObject:artistDescriptor]; NSSortDescriptor *albumYearDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"year" ascending:YES]; diff --git a/Submariner/SBServerLibraryController.m b/Submariner/SBServerLibraryController.m index 5cf4230..cac54de 100644 --- a/Submariner/SBServerLibraryController.m +++ b/Submariner/SBServerLibraryController.m @@ -75,7 +75,7 @@ - (id)initWithManagedObjectContext:(NSManagedObjectContext *)context { if (self) { groupEntity = [NSEntityDescription entityForName: @"Group" inManagedObjectContext: managedObjectContext]; - NSSortDescriptor *artistDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"itemName" ascending:YES selector: @selector(caseInsensitiveCompare:)]; + NSSortDescriptor *artistDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"itemName" ascending:YES selector: @selector(artistListCompare:)]; artistSortDescriptor = [NSArray arrayWithObject:artistDescriptor]; NSSortDescriptor *albumYearDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"year" ascending:YES];