Skip to content
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

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from

Conversation

amuraveinik
Copy link
Contributor

@amuraveinik amuraveinik commented Nov 4, 2024

@amuraveinik amuraveinik requested review from tureck1y and a team as code owners November 4, 2024 10:45
@amuraveinik amuraveinik marked this pull request as draft November 4, 2024 10:45
rowView
}

Text("Please select the correct country to ensure accurate payment options and services.")
Copy link
Contributor Author

@amuraveinik amuraveinik Nov 4, 2024

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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вообще это можно сделать через GroupedSection, там есть footer: который везде через DefaultFooterView делаем

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Я хотел тут использовать по аналогии как в настройках приложения, но:

  1. GroupedSection не подходит тут по отсупам.
  2. DefaultRowView не подходит тут по шрифту
  3. DefaultFooterView не подходит тут по шрифту

Tangem/Modules/OnrampSettings/OnrampSettingsView.swift Outdated Show resolved Hide resolved
Tangem/Modules/OnrampSettings/OnrampSettingsView.swift Outdated Show resolved Hide resolved
namespace: .init(id: namespace.id, names: namespace.names)
namespace: .init(id: namespace.id, names: namespace.names),
selectCurrency: {
viewModel.router?.openOnrampCurrencySelectorView()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Balashov152 Тут нужен комментарий, архитектурно не понимаю куда этот вызов положить.
По идее у OnrampAmountView есть своя вьюмодель, но как оттуда вызвать роутер я не понимаю

Copy link
Contributor

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] {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тут как договаривались - захардкожено просто на клиенте

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Я думаю лучше просто code хардкодить ["GBP", "USD"] целая модель то не нужна

Copy link
Contributor

@Balashov152 Balashov152 left a 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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Лучше в отдельную view. Что то типо OnrampCountryRowView / OnrampCountryRowViewData

Comment on lines 41 to 44
.catch { error in
// TODO: Handle error
return Just([])
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Можно так)

Suggested change
.catch { error in
// TODO: Handle error
return Just([])
}
.replaceError(with: [])

Copy link
Contributor Author

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] = []
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

И здесь будет [OnrampCountryRowViewData]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А пока загрузка идет? Надо наверное через LoadingValue<[OnrampCountryRowViewData]> делать, что бы разные View были

Comment on lines 17 to 20
Colors.Icon.inactive
.frame(width: 32, height: 4)
.cornerRadius(2, corners: .allCorners)
.padding(.vertical, 8)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это есть уже

Suggested change
Colors.Icon.inactive
.frame(width: 32, height: 4)
.cornerRadius(2, corners: .allCorners)
.padding(.vertical, 8)
GrabberViewFactory().makeSwiftUIView()

}
}

private func rowViewLabel(currency: OnrampFiatCurrency) -> some View {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тоже бы в OnrampFiatCurrencyView / OnrampFiatCurrencyViewData

Comment on lines +21 to +22
repository.preferenceCountryPublisher
.assign(to: &$selectedCountry)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

без store(in: ) не имеет смысла же

Suggested change
repository.preferenceCountryPublisher
.assign(to: &$selectedCountry)
selectedCountry = repository.preferenceCountry

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.assign(to: ) работает не так как обычные паблишеры, глянь эпл доку

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Send / Sell / Staking не сломались? Проверь плиз

Copy link
Contributor Author

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()
Copy link
Contributor

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] {
Copy link
Contributor

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> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

а зачем так сложно, можно через Task во ViewModel делать
Это же не паблишер, а только один запрос - ответ

@amuraveinik amuraveinik force-pushed the feature/IOS-8357_onramp_country_currency_settings branch from e38aa41 to 620ca12 Compare November 5, 2024 15:27
@amuraveinik amuraveinik marked this pull request as ready for review November 5, 2024 15:31
@amuraveinik
Copy link
Contributor Author

В общем, я сделал выводы что лучше сразу делать все в разный PRах.
Этот уже сложно разделить, но я сделал разбивку по коммитам к каждой задаче для удобства ревьюера

return items
}

let loweccasedSearchText = searchText.lowercased()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

может еще trimmed ?

Suggested change
let loweccasedSearchText = searchText.lowercased()
let loweccasedSearchText = searchText.lowercased().trimmed()

Comment on lines +31 to +46
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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Как то сложно получается

  1. Можно все сделать через Task, который будет ходить за countries так как они там тоже лежат в кэше.
  2. получается что изначально у тебя self.countries = .loading. Потом ты вызываешь метод updateView(searchText: "") и "без поиска" обновляешь View с данными из репозитория.
  3. По подписке в методе bind() подписываешься на $searchText. и там вызываешь этот же метод updateView(searchText: searchText). Все делаешь в одном Таске, отменяя его, сохранив при этом в проперти класса. И плюс сортировку можно делать тоже в background потоке, и потом просто через await runOnMain {} обновлять список

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ну это уже вкусовщина, абсолютно никакой разницы в функционале нет.
Мне просто удобнее работать с реактивными последовательностями, потому что они тут органичнее встраиваются, например:

  1. $searchText - это поток данных, самый что ни на есть
  2. countriesSubject - тут как бы да, мы в него данные отправляем одноразово после асинхронного запроса, но если помнишь то в предыдущей версии я выкачку данных из репозитория тоже организовал через комбайн.

Короче после нескольких таких итераций получится что ты просто моими руками напишешь код который тебе самому больше нравится)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Либо надо зафиксировать на уровне соглашения такой подход - что в приоритете используем async/await

Comment on lines +16 to +17
let isAvailable: Bool
let isSelected: Bool
Copy link
Contributor

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(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Может переименовать ее как то более общее, а то в Markets поменяют, и даже не знаю что в onramp она же юзается )

Comment on lines +36 to +51
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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тут тоже самое что и в OnrampCountySelectorViewModel

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 18 to 28
VStack(alignment: .leading, spacing: 7) {
SkeletonView()
.frame(width: 70, height: 12)
.cornerRadiusContinuous(3)

SkeletonView()
.frame(width: 52, height: 12)
.cornerRadiusContinuous(3)
}
}
.padding(.vertical, 15)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Как то смущают 15 и 7. Хорошо бы через PixelPerfect проверить, у нас CTO любит такое замечать )

Copy link
Contributor

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

Comment on lines +21 to +22
repository.preferenceCountryPublisher
.assign(to: &$selectedCountry)
Copy link
Contributor

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?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А это не надо делать через отдельный coordinator? Вроде понятно что и так должно работать, но не было бы проблем на старых осях, где SUI дальше чем одна View не может

Copy link
Contributor Author

@amuraveinik amuraveinik Nov 5, 2024

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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

accentColor вроде deprecated. Можно tint использовать

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants