diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj
index 025678de..e2fffb8d 100644
--- a/Mastodon.xcodeproj/project.pbxproj
+++ b/Mastodon.xcodeproj/project.pbxproj
@@ -280,6 +280,7 @@
DB4FFC2C269EC39600D62E92 /* SearchTransitionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB4FFC2A269EC39600D62E92 /* SearchTransitionController.swift */; };
DB51D172262832380062B7A1 /* BlurHashDecode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB51D170262832380062B7A1 /* BlurHashDecode.swift */; };
DB51D173262832380062B7A1 /* BlurHashEncode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB51D171262832380062B7A1 /* BlurHashEncode.swift */; };
+ DB552D4F26BBD10C00E481F6 /* OrderedCollections in Frameworks */ = {isa = PBXBuildFile; productRef = DB552D4E26BBD10C00E481F6 /* OrderedCollections */; };
DB564BD0269F2F83001E39A7 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = DB564BCE269F2F83001E39A7 /* Localizable.stringsdict */; };
DB564BD3269F3B35001E39A7 /* StatusFilterService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB564BD2269F3B35001E39A7 /* StatusFilterService.swift */; };
DB59F0FE25EF5D96001F1DAB /* StatusProvider+UITableViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB59F0FD25EF5D96001F1DAB /* StatusProvider+UITableViewDelegate.swift */; };
@@ -1311,6 +1312,7 @@
DB6804862637CD4C00430867 /* AppShared.framework in Frameworks */,
DBF96326262EC0A6001D8D25 /* AuthenticationServices.framework in Frameworks */,
DBAC6483267D0B21007FE9FD /* DifferenceKit in Frameworks */,
+ DB552D4F26BBD10C00E481F6 /* OrderedCollections in Frameworks */,
2D61336925C18A4F00CAE157 /* AlamofireNetworkActivityIndicator in Frameworks */,
DB01E23326A98F0900C3965B /* MastodonMeta in Frameworks */,
DBAC64A1267E6D02007FE9FD /* Fuzi in Frameworks */,
@@ -3081,6 +3083,7 @@
DBC6462A26A1738900B0E31B /* MastodonUI */,
DB01E23226A98F0900C3965B /* MastodonMeta */,
DB01E23426A98F0900C3965B /* MetaTextKit */,
+ DB552D4E26BBD10C00E481F6 /* OrderedCollections */,
);
productName = Mastodon;
productReference = DB427DD225BAA00100D1B89D /* Mastodon.app */;
@@ -3328,6 +3331,7 @@
DBF7A0FA26830C33004176A2 /* XCRemoteSwiftPackageReference "FPSIndicator" */,
DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin" */,
DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */,
+ DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections" */,
);
productRefGroup = DB427DD325BAA00100D1B89D /* Products */;
projectDirPath = "";
@@ -5644,6 +5648,14 @@
minimumVersion = 4.1.0;
};
};
+ DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections" */ = {
+ isa = XCRemoteSwiftPackageReference;
+ repositoryURL = "https://github.com/apple/swift-collections.git";
+ requirement = {
+ kind = upToNextMajorVersion;
+ minimumVersion = 0.0.5;
+ };
+ };
DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/kishikawakatsumi/KeychainAccess.git";
@@ -5752,6 +5764,11 @@
package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */;
productName = AlamofireImage;
};
+ DB552D4E26BBD10C00E481F6 /* OrderedCollections */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections" */;
+ productName = OrderedCollections;
+ };
DB68050F2637D0F800430867 /* KeychainAccess */ = {
isa = XCSwiftPackageProductDependency;
package = DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess" */;
diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
index 4bf0e25a..09c042d8 100644
--- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -7,12 +7,12 @@
AppShared.xcscheme_^#shared#^_
orderHint
- 24
+ 26
CoreDataStack.xcscheme_^#shared#^_
orderHint
- 25
+ 24
Mastodon - ASDK.xcscheme_^#shared#^_
@@ -42,7 +42,7 @@
MastodonIntent.xcscheme_^#shared#^_
orderHint
- 28
+ 27
MastodonIntents.xcscheme_^#shared#^_
@@ -62,7 +62,7 @@
ShareActionExtension.xcscheme_^#shared#^_
orderHint
- 26
+ 25
SuppressBuildableAutocreation
diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved
index c6a46992..67c613bf 100644
--- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -136,6 +136,15 @@
"version": "5.11.1"
}
},
+ {
+ "package": "swift-collections",
+ "repositoryURL": "https://github.com/apple/swift-collections.git",
+ "state": {
+ "branch": null,
+ "revision": "0959ba76a1d4a98fd11163aa83fd49c25b93bfae",
+ "version": "0.0.5"
+ }
+ },
{
"package": "swift-nio",
"repositoryURL": "https://github.com/apple/swift-nio.git",
diff --git a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel+LoadIndexedServerState.swift b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel+LoadIndexedServerState.swift
index 1cb9b508..0c4910d1 100644
--- a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel+LoadIndexedServerState.swift
+++ b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel+LoadIndexedServerState.swift
@@ -55,13 +55,7 @@ extension MastodonPickServerViewModel.LoadIndexedServerState {
} receiveValue: { [weak self] response in
guard let _ = self else { return }
stateMachine.enter(Idle.self)
-
- // ignore approval required servers
- var servers = response.value
- if viewModel.mode == .signUp {
- servers = servers.filter { !$0.approvalRequired }
- }
- viewModel.indexedServers.value = servers
+ viewModel.indexedServers.value = response.value
}
.store(in: &viewModel.disposeBag)
}
diff --git a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift
index ef9275b0..7a648011 100644
--- a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift
+++ b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift
@@ -11,6 +11,7 @@ import Combine
import GameplayKit
import MastodonSDK
import CoreDataStack
+import OrderedCollections
class MastodonPickServerViewModel: NSObject {
@@ -167,7 +168,44 @@ extension MastodonPickServerViewModel {
searchText.debounce(for: .milliseconds(300), scheduler: DispatchQueue.main).removeDuplicates()
)
.map { indexedServers, selectCategoryItem, searchText -> [Mastodon.Entity.Server] in
- // Filter the indexed servers from joinmastodon.org
+ // ignore approval required servers when sign-up
+ var indexedServers = indexedServers
+ if self.mode == .signUp {
+ indexedServers = indexedServers.filter { !$0.approvalRequired }
+ }
+
+ // group by language user preferred language first. Then sort by `totalUsers`
+ var languageToServersMapping = OrderedDictionary()
+ for language in Locale.preferredLanguages {
+ let local = Locale(identifier: language)
+ guard let languageCode = local.languageCode else { continue }
+ // skip if key duplicate
+ guard !languageToServersMapping.keys.contains(languageCode) else { continue }
+ // append to dict
+ languageToServersMapping[languageCode] = indexedServers
+ .filter { $0.language.lowercased() == languageCode.lowercased() }
+ .sorted(by: { $0.totalUsers > $1.totalUsers })
+ }
+ // sort remains servers by `totalUsers`
+ let remainsServers = indexedServers
+ .filter { server in
+ return !languageToServersMapping.contains { _, servers in servers.contains(server) }
+ }
+ .sorted(by: { $0.totalUsers > $1.totalUsers })
+
+ var _indexedServers: [Mastodon.Entity.Server] = []
+ for key in languageToServersMapping.keys {
+ _indexedServers.append(contentsOf: languageToServersMapping[key] ?? [])
+ }
+ _indexedServers.append(contentsOf: remainsServers)
+
+ if _indexedServers.count == indexedServers.count {
+ indexedServers = _indexedServers
+ } else {
+ assertionFailure("should not change dataset size")
+ }
+
+ // Filter the indexed servers by category or search text
switch selectCategoryItem {
case .all:
return MastodonPickServerViewModel.filterServers(servers: indexedServers, category: nil, searchText: searchText)