Skip to content

Commit c85a865

Browse files
refactor(local-currency): extract CurrencyItem and debounce filtering
1 parent 37ebbca commit c85a865

3 files changed

Lines changed: 59 additions & 21 deletions

File tree

DashWallet.xcodeproj/project.pbxproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,8 @@
507507
5151CD632F926D1900F0A604 /* SearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5151CD612F926D1900F0A604 /* SearchBar.swift */; };
508508
5151CDF02F928D7D00F0A604 /* LocalCurrencyCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5151CDEF2F928D7D00F0A604 /* LocalCurrencyCellView.swift */; };
509509
5151CDF12F928D7D00F0A604 /* LocalCurrencyCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5151CDEF2F928D7D00F0A604 /* LocalCurrencyCellView.swift */; };
510+
5151CE182F9624D000F0A604 /* CurrencyItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5151CE172F9624D000F0A604 /* CurrencyItem.swift */; };
511+
5151CE192F9624D000F0A604 /* CurrencyItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5151CE172F9624D000F0A604 /* CurrencyItem.swift */; };
510512
7502A4872AE401EF00ACDDD3 /* UsernameVotingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7502A4862AE401EF00ACDDD3 /* UsernameVotingViewController.swift */; };
511513
7503643A2C89CFB70029EC0D /* CoinJoinProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 750364392C89CFB70029EC0D /* CoinJoinProgressView.swift */; };
512514
7503643B2C89CFB70029EC0D /* CoinJoinProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 750364392C89CFB70029EC0D /* CoinJoinProgressView.swift */; };
@@ -2475,6 +2477,7 @@
24752477
5151CA222F92335E00F0A604 /* LocalCurrencyViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalCurrencyViewModel.swift; sourceTree = "<group>"; };
24762478
5151CD612F926D1900F0A604 /* SearchBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchBar.swift; sourceTree = "<group>"; };
24772479
5151CDEF2F928D7D00F0A604 /* LocalCurrencyCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalCurrencyCellView.swift; sourceTree = "<group>"; };
2480+
5151CE172F9624D000F0A604 /* CurrencyItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrencyItem.swift; sourceTree = "<group>"; };
24782481
62C1F7A3ABEE7CF3BBB270C4 /* Pods-DashWalletTests.testflight.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DashWalletTests.testflight.xcconfig"; path = "Target Support Files/Pods-DashWalletTests/Pods-DashWalletTests.testflight.xcconfig"; sourceTree = "<group>"; };
24792482
67217DE34817FB304EDEA8D4 /* Pods-dashpay.testnet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-dashpay.testnet.xcconfig"; path = "Target Support Files/Pods-dashpay/Pods-dashpay.testnet.xcconfig"; sourceTree = "<group>"; };
24802483
6A44C167AF8F881176AFB256 /* Pods-TodayExtension.testflight.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TodayExtension.testflight.xcconfig"; path = "Target Support Files/Pods-TodayExtension/Pods-TodayExtension.testflight.xcconfig"; sourceTree = "<group>"; };
@@ -4332,6 +4335,7 @@
43324335
2AA87CF926E5681100F0CEA6 /* DWCurrencyObject.m */,
43334336
2ACD53E6234BADD300650AD3 /* DWCurrencyItem.h */,
43344337
2AA87CFB26E568A100F0CEA6 /* DWCurrencyItemPriceProvider.h */,
4338+
5151CE172F9624D000F0A604 /* CurrencyItem.swift */,
43354339
);
43364340
path = LocalCurrency;
43374341
sourceTree = "<group>";
@@ -8668,6 +8672,7 @@
86688672
47AE8BF428C1306000490F5E /* FetchingNextPageCell.swift in Sources */,
86698673
47081197298CF20C003FCA3D /* Transaction.swift in Sources */,
86708674
47AE8BE628C1305F00490F5E /* AllMerchantLocationsViewController.swift in Sources */,
8675+
5151CE192F9624D000F0A604 /* CurrencyItem.swift in Sources */,
86718676
2ACCD84D23180E7E00A96B62 /* DWPaymentOutput.m in Sources */,
86728677
2AB3415E23A8133A004E37A7 /* DWPayModelStub.m in Sources */,
86738678
2A74EFF1230531DA00C475EB /* DWRecoverContentView.m in Sources */,
@@ -9337,6 +9342,7 @@
93379342
C9D2C6BB2A320AA000D15901 /* DWFormTableViewController.m in Sources */,
93389343
C943B34D2A40A4C500AF23C5 /* DWInfoPopupViewController.m in Sources */,
93399344
75F990822AFD1065006759AB /* UsernameRequestDetailsViewController.swift in Sources */,
9345+
5151CE182F9624D000F0A604 /* CurrencyItem.swift in Sources */,
93409346
C943B32A2A408CED00AF23C5 /* DWAvatarExternalSourceView.m in Sources */,
93419347
C9D2C6BC2A320AA000D15901 /* WalletKeysOverviewModel.swift in Sources */,
93429348
C9D2C6BD2A320AA000D15901 /* UIAssembly.swift in Sources */,
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//
2+
// Created by Roman Chornyi
3+
// Copyright © 2026 Dash Core Group. All rights reserved.
4+
//
5+
// Licensed under the MIT License (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// https://opensource.org/licenses/MIT
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
//
17+
18+
import Foundation
19+
20+
struct CurrencyItem: Identifiable, Equatable {
21+
var id: String { code }
22+
let code: String
23+
let name: String
24+
let flagName: String?
25+
let priceString: String?
26+
}

DashWallet/Sources/UI/Menu/Settings/LocalCurrency/LocalCurrencyViewModel.swift

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,34 +18,15 @@
1818
import Foundation
1919
import Combine
2020

21-
// MARK: - CurrencyItem
22-
23-
struct CurrencyItem: Identifiable, Equatable {
24-
var id: String { code }
25-
let code: String
26-
let name: String
27-
let flagName: String?
28-
let priceString: String?
29-
}
30-
31-
// MARK: - LocalCurrencyViewModel
32-
3321
@MainActor
3422
class LocalCurrencyViewModel: ObservableObject {
3523
private let allItems: [CurrencyItem]
24+
private var cancellables = Set<AnyCancellable>()
3625

3726
@Published var searchQuery: String = ""
27+
@Published private(set) var filteredItems: [CurrencyItem] = []
3828
@Published var selectedCurrencyCode: String
3929

40-
var filteredItems: [CurrencyItem] {
41-
let trimmed = searchQuery.trimmingCharacters(in: .whitespaces)
42-
guard !trimmed.isEmpty else { return allItems }
43-
let query = trimmed.lowercased()
44-
return allItems.filter {
45-
$0.code.lowercased().contains(query) || $0.name.lowercased().contains(query)
46-
}
47-
}
48-
4930
/// Production init — loads currencies from CurrencyExchangerObjcWrapper.
5031
init(currencyCode: String? = nil) {
5132
let formatter = NumberFormatter()
@@ -62,18 +43,43 @@ class LocalCurrencyViewModel: ObservableObject {
6243
}
6344
self.allItems = items
6445
self.selectedCurrencyCode = currencyCode ?? App.fiatCurrency
46+
self.filteredItems = items
47+
setupSearch()
6548
}
6649

6750
/// Preview / testing init — accepts pre-built items without DashSync.
6851
init(items: [CurrencyItem], selectedCode: String) {
6952
self.allItems = items
7053
self.selectedCurrencyCode = selectedCode
54+
self.filteredItems = items
55+
setupSearch()
7156
}
7257

7358
func select(currencyCode: String) {
7459
selectedCurrencyCode = currencyCode
7560
App.shared.fiatCurrency = currencyCode
7661
}
62+
63+
private func setupSearch() {
64+
$searchQuery
65+
.debounce(for: .milliseconds(150), scheduler: RunLoop.main)
66+
.sink { [weak self] query in
67+
self?.applyFilter(query)
68+
}
69+
.store(in: &cancellables)
70+
}
71+
72+
private func applyFilter(_ query: String) {
73+
let trimmed = query.trimmingCharacters(in: .whitespaces)
74+
guard !trimmed.isEmpty else {
75+
filteredItems = allItems
76+
return
77+
}
78+
let lowercased = trimmed.lowercased()
79+
filteredItems = allItems.filter {
80+
$0.code.lowercased().contains(lowercased) || $0.name.lowercased().contains(lowercased)
81+
}
82+
}
7783
}
7884

7985
// MARK: - Flag mapping

0 commit comments

Comments
 (0)