-
Notifications
You must be signed in to change notification settings - Fork 36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IOS-8357 IOS-8158 IOS-8358 [Onramp] Country + Currency + Settings #4155
base: develop
Are you sure you want to change the base?
IOS-8357 IOS-8158 IOS-8358 [Onramp] Country + Currency + Settings #4155
Conversation
Tangem/Modules/OnrampCountrySelector/OnrampCountrySelectorView.swift
Outdated
Show resolved
Hide resolved
Tangem/Modules/OnrampCountrySelector/OnrampCountrySelectorView.swift
Outdated
Show resolved
Hide resolved
Tangem/Modules/OnrampCurrencySelect/OnrampCurrencySelectorView.swift
Outdated
Show resolved
Hide resolved
rowView | ||
} | ||
|
||
Text("Please select the correct country to ensure accurate payment options and services.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: Lokalise onramp_settings_residence_description
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Вообще это можно сделать через GroupedSection, там есть footer: который везде через DefaultFooterView
делаем
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Я хотел тут использовать по аналогии как в настройках приложения, но:
- GroupedSection не подходит тут по отсупам.
- DefaultRowView не подходит тут по шрифту
- DefaultFooterView не подходит тут по шрифту
namespace: .init(id: namespace.id, names: namespace.names) | ||
namespace: .init(id: namespace.id, names: namespace.names), | ||
selectCurrency: { | ||
viewModel.router?.openOnrampCurrencySelectorView() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Balashov152 Тут нужен комментарий, архитектурно не понимаю куда этот вызов положить.
По идее у OnrampAmountView есть своя вьюмодель, но как оттуда вызвать роутер я не понимаю
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
не, точно не тут
Получается надо добавить OnrampAmountRoutable
с этим методом, и потом проставить router в OnrampAmountViewModel
, в OnrampFlowBaseBuilder
и уже через router открыть, а сам OnrampAmountRoutable
будет SendViewModel
подерживать, так же как и OnrampSummaryRoutable
public protocol OnrampDataRepository: Actor { | ||
func paymentMethods() async throws -> [OnrampPaymentMethod] | ||
func countries() async throws -> [OnrampCountry] | ||
func currencies() async throws -> [OnrampFiatCurrency] | ||
} | ||
|
||
public extension OnrampDataRepository { | ||
var popularFiats: [OnrampFiatCurrency] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Тут как договаривались - захардкожено просто на клиенте
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Я думаю лучше просто code
хардкодить ["GBP", "USD"] целая модель то не нужна
Tangem/Modules/OnrampCurrencySelect/OnrampCurrencySelectorViewModel.swift
Outdated
Show resolved
Hide resolved
Tangem/Modules/OnrampCurrencySelect/OnrampCurrencySelectorViewModel.swift
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Вообще правильно одна задача - один MR. Плюс там есть апдейт по дизайну с error
и loading
стейтами. Тут много достаточно что бы хорошо посмотреть
} | ||
} | ||
|
||
private func rowViewLabel(country: OnrampCountry) -> some View { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Лучше в отдельную view. Что то типо OnrampCountryRowView
/ OnrampCountryRowViewData
.catch { error in | ||
// TODO: Handle error | ||
return Just([]) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Можно так)
.catch { error in | |
// TODO: Handle error | |
return Just([]) | |
} | |
.replaceError(with: []) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Стало неактуально как только появились стейты ошбика
final class OnrampCountrySelectorViewModel: Identifiable, ObservableObject { | ||
let preferenceCountry: OnrampCountry? | ||
@Published var searchText: String = "" | ||
@Published private(set) var countries: [OnrampCountry] = [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
И здесь будет [OnrampCountryRowViewData]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
А пока загрузка идет? Надо наверное через LoadingValue<[OnrampCountryRowViewData]>
делать, что бы разные View были
Colors.Icon.inactive | ||
.frame(width: 32, height: 4) | ||
.cornerRadius(2, corners: .allCorners) | ||
.padding(.vertical, 8) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Это есть уже
Colors.Icon.inactive | |
.frame(width: 32, height: 4) | |
.cornerRadius(2, corners: .allCorners) | |
.padding(.vertical, 8) | |
GrabberViewFactory().makeSwiftUIView() |
} | ||
} | ||
|
||
private func rowViewLabel(currency: OnrampFiatCurrency) -> some View { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Тоже бы в OnrampFiatCurrencyView
/ OnrampFiatCurrencyViewData
repository.preferenceCountryPublisher | ||
.assign(to: &$selectedCountry) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
без store(in: )
не имеет смысла же
repository.preferenceCountryPublisher | |
.assign(to: &$selectedCountry) | |
selectedCountry = repository.preferenceCountry |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.assign(to: ) работает не так как обычные паблишеры, глянь эпл доку
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
хм, интересно, не знал
SendView(viewModel: rootViewModel, transitionService: .init()) | ||
.navigationLinks(links) | ||
} | ||
NavigationView { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Send / Sell / Staking не сломались? Проверь плиз
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Вроде все ок
namespace: .init(id: namespace.id, names: namespace.names) | ||
namespace: .init(id: namespace.id, names: namespace.names), | ||
selectCurrency: { | ||
viewModel.router?.openOnrampCurrencySelectorView() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
не, точно не тут
Получается надо добавить OnrampAmountRoutable
с этим методом, и потом проставить router в OnrampAmountViewModel
, в OnrampFlowBaseBuilder
и уже через router открыть, а сам OnrampAmountRoutable
будет SendViewModel
подерживать, так же как и OnrampSummaryRoutable
public protocol OnrampDataRepository: Actor { | ||
func paymentMethods() async throws -> [OnrampPaymentMethod] | ||
func countries() async throws -> [OnrampCountry] | ||
func currencies() async throws -> [OnrampFiatCurrency] | ||
} | ||
|
||
public extension OnrampDataRepository { | ||
var popularFiats: [OnrampFiatCurrency] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Я думаю лучше просто code
хардкодить ["GBP", "USD"] целая модель то не нужна
} | ||
|
||
public extension OnrampDataRepository { | ||
nonisolated var countriesPublisher: AnyPublisher<[OnrampCountry], Error> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
а зачем так сложно, можно через Task во ViewModel делать
Это же не паблишер, а только один запрос - ответ
e38aa41
to
620ca12
Compare
В общем, я сделал выводы что лучше сразу делать все в разный PRах. |
return items | ||
} | ||
|
||
let loweccasedSearchText = searchText.lowercased() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
может еще trimmed
?
let loweccasedSearchText = searchText.lowercased() | |
let loweccasedSearchText = searchText.lowercased().trimmed() |
Publishers.CombineLatest( | ||
countriesSubject, | ||
$searchText | ||
) | ||
.withWeakCaptureOf(self) | ||
.map { viewModel, data in | ||
let (countries, searchText) = data | ||
return .loaded( | ||
viewModel.mapToCountriesViewData( | ||
countries: countries, | ||
searchText: searchText | ||
) | ||
) | ||
} | ||
.receive(on: DispatchQueue.main) | ||
.assign(to: &$countries) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Как то сложно получается
- Можно все сделать через Task, который будет ходить за
countries
так как они там тоже лежат в кэше. - получается что изначально у тебя self.countries = .loading. Потом ты вызываешь метод
updateView(searchText: "")
и "без поиска" обновляешь View с данными из репозитория. - По подписке в методе
bind()
подписываешься на $searchText. и там вызываешь этот же методupdateView(searchText: searchText)
. Все делаешь в одном Таске, отменяя его, сохранив при этом в проперти класса. И плюс сортировку можно делать тоже в background потоке, и потом просто черезawait runOnMain {}
обновлять список
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ну это уже вкусовщина, абсолютно никакой разницы в функционале нет.
Мне просто удобнее работать с реактивными последовательностями, потому что они тут органичнее встраиваются, например:
$searchText
- это поток данных, самый что ни на естьcountriesSubject
- тут как бы да, мы в него данные отправляем одноразово после асинхронного запроса, но если помнишь то в предыдущей версии я выкачку данных из репозитория тоже организовал через комбайн.
Короче после нескольких таких итераций получится что ты просто моими руками напишешь код который тебе самому больше нравится)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Либо надо зафиксировать на уровне соглашения такой подход - что в приоритете используем async/await
let isAvailable: Bool | ||
let isSelected: Bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Как будто можно через enum DetailsType
сделать, что бы по switch case во View проходить, но так тоже норм )
var failedToLoadView: some View { | ||
Spacer() | ||
|
||
MarketsUnableToLoadDataView( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Может переименовать ее как то более общее, а то в Markets поменяют, и даже не знаю что в onramp она же юзается )
Publishers.CombineLatest( | ||
currenciesSubject, | ||
$searchText | ||
) | ||
.withWeakCaptureOf(self) | ||
.map { viewModel, data in | ||
let (currencies, searchText) = data | ||
return .loaded( | ||
viewModel.mapToState( | ||
currencies: currencies, | ||
searchText: searchText | ||
) | ||
) | ||
} | ||
.receive(on: DispatchQueue.main) | ||
.assign(to: &$currencies) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Тут тоже самое что и в OnrampCountySelectorViewModel
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
VStack(alignment: .leading, spacing: 7) { | ||
SkeletonView() | ||
.frame(width: 70, height: 12) | ||
.cornerRadiusContinuous(3) | ||
|
||
SkeletonView() | ||
.frame(width: 52, height: 12) | ||
.cornerRadiusContinuous(3) | ||
} | ||
} | ||
.padding(.vertical, 15) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Как то смущают 15 и 7. Хорошо бы через PixelPerfect проверить, у нас CTO любит такое замечать )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Глянь плиз в остальных местах, есть вот ответ от дизайна что должно быть 14 везде
https://www.figma.com/design/ZJoUO3kZGCcVgOUbCMQcY4?node-id=38164-85535#1013677827
repository.preferenceCountryPublisher | ||
.assign(to: &$selectedCountry) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
хм, интересно, не знал
@Published var onrampCountryViewModel: OnrampCountryViewModel? | ||
@Published var onrampCountryDetectionViewModel: OnrampCountryDetectionViewModel? | ||
|
||
@Published var onrampSettingsViewModel: OnrampSettingsViewModel? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
А это не надо делать через отдельный coordinator
? Вроде понятно что и так должно работать, но не было бы проблем на старых осях, где SUI дальше чем одна View не может
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Потестил на
- 18.0
- 17.5
- 16.4
- 15.5
По этому флоу все ок
} | ||
.accentColor(Colors.Text.primary1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
accentColor
вроде deprecated
. Можно tint
использовать
IOS-8357
IOS-8158
IOS-8358