feat: resolve requested changes
This commit is contained in:
parent
7329a62582
commit
8476fc0e38
|
@ -41,6 +41,18 @@
|
|||
},
|
||||
"server_picker": {
|
||||
"title": "Pick a Server,\nany server.",
|
||||
"Button": {
|
||||
"Category": {
|
||||
"All": "All"
|
||||
},
|
||||
"SeeLess": "See Less",
|
||||
"SeeMore": "See More"
|
||||
},
|
||||
"Label": {
|
||||
"Language": "LANGUAGE",
|
||||
"Users": "USERS",
|
||||
"Category": "CATEGORY"
|
||||
},
|
||||
"input": {
|
||||
"placeholder": "Find a server or join your own..."
|
||||
}
|
||||
|
|
|
@ -29,7 +29,13 @@
|
|||
"Scene.Register.Input.Username.DuplicatePrompt" = "This username is taken.";
|
||||
"Scene.Register.Input.Username.Placeholder" = "username";
|
||||
"Scene.Register.Title" = "Tell us about you.";
|
||||
"Scene.ServerPicker.Button.Category.All" = "All";
|
||||
"Scene.ServerPicker.Button.Seeless" = "See Less";
|
||||
"Scene.ServerPicker.Button.Seemore" = "See More";
|
||||
"Scene.ServerPicker.Input.Placeholder" = "Find a server or join your own...";
|
||||
"Scene.ServerPicker.Label.Category" = "CATEGORY";
|
||||
"Scene.ServerPicker.Label.Language" = "LANGUAGE";
|
||||
"Scene.ServerPicker.Label.Users" = "USERS";
|
||||
"Scene.ServerPicker.Title" = "Pick a Server,
|
||||
any server.";
|
||||
"Scene.ServerRules.Button.Confirm" = "I Agree";
|
||||
|
|
|
@ -41,6 +41,18 @@
|
|||
},
|
||||
"server_picker": {
|
||||
"title": "Pick a Server,\nany server.",
|
||||
"Button": {
|
||||
"Category": {
|
||||
"All": "All"
|
||||
},
|
||||
"SeeLess": "See Less",
|
||||
"SeeMore": "See More"
|
||||
},
|
||||
"Label": {
|
||||
"Language": "LANGUAGE",
|
||||
"Users": "USERS",
|
||||
"Category": "CATEGORY"
|
||||
},
|
||||
"input": {
|
||||
"placeholder": "Find a server or join your own..."
|
||||
}
|
||||
|
|
|
@ -111,10 +111,10 @@ internal enum L10n {
|
|||
/// Pick a Server,\nany server.
|
||||
internal static let title = L10n.tr("Localizable", "Scene.ServerPicker.Title")
|
||||
internal enum Button {
|
||||
/// See less
|
||||
internal static let seeLess = L10n.tr("Localizable", "Scene.ServerPicker.Button.SeeLess")
|
||||
/// See Less
|
||||
internal static let seeless = L10n.tr("Localizable", "Scene.ServerPicker.Button.Seeless")
|
||||
/// See More
|
||||
internal static let seeMore = L10n.tr("Localizable", "Scene.ServerPicker.Button.SeeMore")
|
||||
internal static let seemore = L10n.tr("Localizable", "Scene.ServerPicker.Button.Seemore")
|
||||
internal enum Category {
|
||||
/// All
|
||||
internal static let all = L10n.tr("Localizable", "Scene.ServerPicker.Button.Category.All")
|
||||
|
|
|
@ -29,19 +29,18 @@
|
|||
"Scene.Register.Input.Username.DuplicatePrompt" = "This username is taken.";
|
||||
"Scene.Register.Input.Username.Placeholder" = "username";
|
||||
"Scene.Register.Title" = "Tell us about you.";
|
||||
"Scene.ServerPicker.Input.Placeholder" = "Find a server or join your own...";
|
||||
"Scene.ServerPicker.Title" = "Pick a Server,
|
||||
any server.";
|
||||
"Scene.ServerPicker.Button.Category.All" = "All";
|
||||
"Scene.ServerPicker.Button.SeeLess" = "See less";
|
||||
"Scene.ServerPicker.Button.SeeMore" = "See More";
|
||||
"Scene.ServerPicker.Button.Seeless" = "See Less";
|
||||
"Scene.ServerPicker.Button.Seemore" = "See More";
|
||||
"Scene.ServerPicker.Input.Placeholder" = "Find a server or join your own...";
|
||||
"Scene.ServerPicker.Label.Category" = "CATEGORY";
|
||||
"Scene.ServerPicker.Label.Language" = "LANGUAGE";
|
||||
"Scene.ServerPicker.Label.Users" = "USERS";
|
||||
"Scene.ServerPicker.Label.Category" = "CATEGORY";
|
||||
|
||||
"Scene.ServerPicker.Title" = "Pick a Server,
|
||||
any server.";
|
||||
"Scene.ServerRules.Button.Confirm" = "I Agree";
|
||||
"Scene.ServerRules.Prompt" = "By continuing, you're subject to the terms of service and privacy policy for %@.";
|
||||
"Scene.ServerRules.Subtitle" = "These rules are set by the admins of %@.";
|
||||
"Scene.ServerRules.Title" = "Some ground rules.";
|
||||
"Scene.Welcome.Slogan" = "Social networking
|
||||
back in your hands.";
|
||||
back in your hands.";
|
||||
|
|
|
@ -19,6 +19,17 @@ final class PickServerViewController: UIViewController, NeedsDependency {
|
|||
|
||||
var viewModel: PickServerViewModel!
|
||||
|
||||
private var isAuthenticating = CurrentValueSubject<Bool, Never>(false)
|
||||
|
||||
private var expandServerDomainSet = Set<String>()
|
||||
|
||||
enum Section: CaseIterable {
|
||||
case title
|
||||
case categories
|
||||
case search
|
||||
case serverList
|
||||
}
|
||||
|
||||
let tableView: UITableView = {
|
||||
let tableView = ControlContainableTableView()
|
||||
tableView.register(PickServerTitleCell.self, forCellReuseIdentifier: String(describing: PickServerTitleCell.self))
|
||||
|
@ -69,16 +80,16 @@ extension PickServerViewController {
|
|||
])
|
||||
|
||||
switch viewModel.mode {
|
||||
case .SignIn:
|
||||
case .signIn:
|
||||
nextStepButton.setTitle(L10n.Common.Controls.Actions.signIn, for: .normal)
|
||||
case .SignUp:
|
||||
case .signUp:
|
||||
nextStepButton.setTitle(L10n.Common.Controls.Actions.continue, for: .normal)
|
||||
}
|
||||
nextStepButton.addTarget(self, action: #selector(nextStepButtonDidClicked(_:)), for: .touchUpInside)
|
||||
|
||||
viewModel.tableView = tableView
|
||||
tableView.delegate = viewModel
|
||||
tableView.dataSource = viewModel
|
||||
// viewModel.tableView = tableView
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
|
||||
viewModel
|
||||
.searchedServers
|
||||
|
@ -139,6 +150,16 @@ extension PickServerViewController {
|
|||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
isAuthenticating
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] loading in
|
||||
if loading {
|
||||
self?.nextStepButton.showLoading()
|
||||
} else {
|
||||
self?.nextStepButton.stopLoading()
|
||||
}
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
viewModel.fetchAllServers()
|
||||
}
|
||||
|
@ -151,15 +172,16 @@ extension PickServerViewController {
|
|||
@objc
|
||||
private func nextStepButtonDidClicked(_ sender: UIButton) {
|
||||
switch viewModel.mode {
|
||||
case .SignIn:
|
||||
case .signIn:
|
||||
doSignIn()
|
||||
case .SignUp:
|
||||
case .signUp:
|
||||
doSignUp()
|
||||
}
|
||||
}
|
||||
|
||||
private func doSignIn() {
|
||||
guard let server = viewModel.selectedServer.value else { return }
|
||||
isAuthenticating.send(true)
|
||||
context.apiService.createApplication(domain: server.domain)
|
||||
.tryMap { response -> PickServerViewModel.AuthenticateInfo in
|
||||
let application = response.value
|
||||
|
@ -171,7 +193,7 @@ extension PickServerViewController {
|
|||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] completion in
|
||||
guard let self = self else { return }
|
||||
// self.viewModel.isAuthenticating.value = false
|
||||
self.isAuthenticating.send(false)
|
||||
|
||||
switch completion {
|
||||
case .failure(let error):
|
||||
|
@ -199,7 +221,7 @@ extension PickServerViewController {
|
|||
private func doSignUp() {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
guard let server = viewModel.selectedServer.value else { return }
|
||||
// viewModel.isRegistering.value = true
|
||||
isAuthenticating.send(true)
|
||||
|
||||
context.apiService.instance(domain: server.domain)
|
||||
.compactMap { [weak self] response -> AnyPublisher<PickServerViewModel.SignUpResponseFirst, Error>? in
|
||||
|
@ -235,7 +257,7 @@ extension PickServerViewController {
|
|||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] completion in
|
||||
guard let self = self else { return }
|
||||
// self.viewModel.isRegistering.value = false
|
||||
self.isAuthenticating.send(false)
|
||||
|
||||
switch completion {
|
||||
case .failure(let error):
|
||||
|
@ -256,3 +278,140 @@ extension PickServerViewController {
|
|||
.store(in: &disposeBag)
|
||||
}
|
||||
}
|
||||
|
||||
extension PickServerViewController: UITableViewDelegate {
|
||||
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
||||
let category = Section.allCases[section]
|
||||
switch category {
|
||||
case .title:
|
||||
return 20
|
||||
case .categories:
|
||||
// Since category view has a blur shadow effect, its height need to be large than the actual height,
|
||||
// Thus we reduce the section header's height by 10, and make the category cell height 60+20(10 inset for top and bottom)
|
||||
return 10
|
||||
case .search:
|
||||
// Same reason as above
|
||||
return 10
|
||||
case .serverList:
|
||||
// Header with 1 height as the separator
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
|
||||
if tableView.indexPathForSelectedRow == indexPath {
|
||||
tableView.deselectRow(at: indexPath, animated: false)
|
||||
viewModel.selectedServer.send(nil)
|
||||
return nil
|
||||
}
|
||||
return indexPath
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none)
|
||||
viewModel.selectedServer.send(viewModel.searchedServers.value[indexPath.row])
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
|
||||
tableView.deselectRow(at: indexPath, animated: false)
|
||||
viewModel.selectedServer.send(nil)
|
||||
}
|
||||
}
|
||||
|
||||
extension PickServerViewController: UITableViewDataSource {
|
||||
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
|
||||
return UIView()
|
||||
}
|
||||
|
||||
func numberOfSections(in tableView: UITableView) -> Int {
|
||||
return Self.Section.allCases.count
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
let section = Self.Section.allCases[section]
|
||||
switch section {
|
||||
case .title,
|
||||
.categories,
|
||||
.search:
|
||||
return 1
|
||||
case .serverList:
|
||||
return viewModel.searchedServers.value.count
|
||||
}
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
|
||||
let section = Self.Section.allCases[indexPath.section]
|
||||
switch section {
|
||||
case .title:
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: PickServerTitleCell.self), for: indexPath) as! PickServerTitleCell
|
||||
return cell
|
||||
case .categories:
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: PickServerCategoriesCell.self), for: indexPath) as! PickServerCategoriesCell
|
||||
cell.dataSource = self
|
||||
cell.delegate = self
|
||||
return cell
|
||||
case .search:
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: PickServerSearchCell.self), for: indexPath) as! PickServerSearchCell
|
||||
cell.delegate = self
|
||||
return cell
|
||||
case .serverList:
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: PickServerCell.self), for: indexPath) as! PickServerCell
|
||||
let server = viewModel.searchedServers.value[indexPath.row]
|
||||
cell.server = server
|
||||
if expandServerDomainSet.contains(server.domain) {
|
||||
cell.mode = .expand
|
||||
} else {
|
||||
cell.mode = .collapse
|
||||
}
|
||||
if server == viewModel.selectedServer.value {
|
||||
tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none)
|
||||
} else {
|
||||
tableView.deselectRow(at: indexPath, animated: false)
|
||||
}
|
||||
|
||||
cell.delegate = self
|
||||
return cell
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension PickServerViewController: PickServerCellDelegate {
|
||||
func pickServerCell(modeChange server: Mastodon.Entity.Server, newMode: PickServerCell.Mode, updates: (() -> Void)) {
|
||||
if newMode == .collapse {
|
||||
expandServerDomainSet.remove(server.domain)
|
||||
} else {
|
||||
expandServerDomainSet.insert(server.domain)
|
||||
}
|
||||
|
||||
tableView.performBatchUpdates(updates) { _ in
|
||||
if let modeChangeIndex = self.viewModel.searchedServers.value.firstIndex(where: { $0 == server }) {
|
||||
self.tableView.scrollToRow(at: IndexPath(row: modeChangeIndex, section: 3), at: .bottom, animated: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension PickServerViewController: PickServerSearchCellDelegate {
|
||||
func pickServerSearchCell(didChange searchText: String?) {
|
||||
viewModel.searchText.send(searchText)
|
||||
}
|
||||
}
|
||||
|
||||
extension PickServerViewController: PickServerCategoriesDataSource, PickServerCategoriesDelegate {
|
||||
func numberOfCategories() -> Int {
|
||||
return viewModel.categories.count
|
||||
}
|
||||
|
||||
func category(at index: Int) -> PickServerViewModel.Category {
|
||||
return viewModel.categories[index]
|
||||
}
|
||||
|
||||
func selectedIndex() -> Int {
|
||||
return viewModel.selectCategoryIndex.value
|
||||
}
|
||||
|
||||
func pickServerCategoriesCell(didSelect index: Int) {
|
||||
return viewModel.selectCategoryIndex.send(index)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,28 +13,21 @@ import CoreDataStack
|
|||
|
||||
class PickServerViewModel: NSObject {
|
||||
enum PickServerMode {
|
||||
case SignUp
|
||||
case SignIn
|
||||
}
|
||||
|
||||
enum Section: CaseIterable {
|
||||
case title
|
||||
case categories
|
||||
case search
|
||||
case serverList
|
||||
case signUp
|
||||
case signIn
|
||||
}
|
||||
|
||||
enum Category {
|
||||
// `All` means search for all categories
|
||||
case All
|
||||
// `Some` means search for specific category
|
||||
case Some(Mastodon.Entity.Category)
|
||||
// `all` means search for all categories
|
||||
case all
|
||||
// `some` means search for specific category
|
||||
case some(Mastodon.Entity.Category)
|
||||
|
||||
var title: String {
|
||||
switch self {
|
||||
case .All:
|
||||
case .all:
|
||||
return L10n.Scene.ServerPicker.Button.Category.all
|
||||
case .Some(let masCategory):
|
||||
case .some(let masCategory):
|
||||
// TODO: Use emoji as placeholders
|
||||
switch masCategory.category {
|
||||
case .academia:
|
||||
|
@ -87,7 +80,7 @@ class PickServerViewModel: NSObject {
|
|||
|
||||
weak var tableView: UITableView?
|
||||
|
||||
private var expandServerDomainSet = Set<String>()
|
||||
// private var expandServerDomainSet = Set<String>()
|
||||
|
||||
var mastodonPinBasedAuthenticationViewController: UIViewController?
|
||||
|
||||
|
@ -101,8 +94,8 @@ class PickServerViewModel: NSObject {
|
|||
|
||||
private func configure() {
|
||||
let masCategories = context.apiService.stubCategories()
|
||||
categories.append(.All)
|
||||
categories.append(contentsOf: masCategories.map { Category.Some($0) })
|
||||
categories.append(.all)
|
||||
categories.append(contentsOf: masCategories.map { Category.some($0) })
|
||||
|
||||
Publishers.CombineLatest3(
|
||||
selectCategoryIndex,
|
||||
|
@ -148,8 +141,8 @@ class PickServerViewModel: NSObject {
|
|||
|
||||
func fetchAllServers() {
|
||||
context.apiService.servers(language: nil, category: nil)
|
||||
.sink { error in
|
||||
print("11")
|
||||
.sink { completion in
|
||||
// TODO: Add a reload button when fails to fetch servers initially
|
||||
} receiveValue: { [weak self] result in
|
||||
self?.allServers.send(result.value)
|
||||
}
|
||||
|
@ -162,9 +155,9 @@ class PickServerViewModel: NSObject {
|
|||
// 1. Filter the category
|
||||
.filter {
|
||||
switch category {
|
||||
case .All:
|
||||
case .all:
|
||||
return true
|
||||
case .Some(let masCategory):
|
||||
case .some(let masCategory):
|
||||
return $0.category.caseInsensitiveCompare(masCategory.category.rawValue) == .orderedSame
|
||||
}
|
||||
}
|
||||
|
@ -179,140 +172,6 @@ class PickServerViewModel: NSObject {
|
|||
}
|
||||
}
|
||||
|
||||
extension PickServerViewModel: UITableViewDelegate {
|
||||
|
||||
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
||||
let category = Section.allCases[section]
|
||||
switch category {
|
||||
case .title:
|
||||
return 20
|
||||
case .categories:
|
||||
// Since category view has a blur shadow effect, its height need to be large than the actual height,
|
||||
// Thus we reduce the section header's height by 10, and make the category cell height 60+20(10 inset for top and bottom)
|
||||
return 10
|
||||
case .search:
|
||||
// Same reason as above
|
||||
return 10
|
||||
case .serverList:
|
||||
// Header with 1 height as the separator
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
|
||||
if tableView.indexPathForSelectedRow == indexPath {
|
||||
tableView.deselectRow(at: indexPath, animated: false)
|
||||
selectedServer.send(nil)
|
||||
return nil
|
||||
}
|
||||
return indexPath
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none)
|
||||
selectedServer.send(searchedServers.value[indexPath.row])
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
|
||||
tableView.deselectRow(at: indexPath, animated: false)
|
||||
selectedServer.send(nil)
|
||||
}
|
||||
}
|
||||
|
||||
extension PickServerViewModel: UITableViewDataSource {
|
||||
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
|
||||
return UIView()
|
||||
}
|
||||
|
||||
func numberOfSections(in tableView: UITableView) -> Int {
|
||||
return Self.Section.allCases.count
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
let section = Self.Section.allCases[section]
|
||||
switch section {
|
||||
case .title,
|
||||
.categories,
|
||||
.search:
|
||||
return 1
|
||||
case .serverList:
|
||||
return searchedServers.value.count
|
||||
}
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
|
||||
let section = Self.Section.allCases[indexPath.section]
|
||||
switch section {
|
||||
case .title:
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: PickServerTitleCell.self), for: indexPath) as! PickServerTitleCell
|
||||
return cell
|
||||
case .categories:
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: PickServerCategoriesCell.self), for: indexPath) as! PickServerCategoriesCell
|
||||
cell.dataSource = self
|
||||
cell.delegate = self
|
||||
return cell
|
||||
case .search:
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: PickServerSearchCell.self), for: indexPath) as! PickServerSearchCell
|
||||
cell.delegate = self
|
||||
return cell
|
||||
case .serverList:
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: PickServerCell.self), for: indexPath) as! PickServerCell
|
||||
let server = searchedServers.value[indexPath.row]
|
||||
cell.server = server
|
||||
if expandServerDomainSet.contains(server.domain) {
|
||||
cell.mode = .expand
|
||||
} else {
|
||||
cell.mode = .collapse
|
||||
}
|
||||
if server == selectedServer.value {
|
||||
tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none)
|
||||
} else {
|
||||
tableView.deselectRow(at: indexPath, animated: false)
|
||||
}
|
||||
|
||||
cell.delegate = self
|
||||
return cell
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension PickServerViewModel: PickServerCategoriesDataSource, PickServerCategoriesDelegate {
|
||||
func numberOfCategories() -> Int {
|
||||
return categories.count
|
||||
}
|
||||
|
||||
func category(at index: Int) -> Category {
|
||||
return categories[index]
|
||||
}
|
||||
|
||||
func selectedIndex() -> Int {
|
||||
return selectCategoryIndex.value
|
||||
}
|
||||
|
||||
func pickServerCategoriesCell(didSelect index: Int) {
|
||||
selectCategoryIndex.send(index)
|
||||
}
|
||||
}
|
||||
|
||||
extension PickServerViewModel: PickServerSearchCellDelegate {
|
||||
func pickServerSearchCell(didChange searchText: String?) {
|
||||
self.searchText.send(searchText)
|
||||
}
|
||||
}
|
||||
|
||||
extension PickServerViewModel: PickServerCellDelegate {
|
||||
func pickServerCell(modeChange server: Mastodon.Entity.Server, newMode: PickServerCell.Mode, updates: (() -> Void)) {
|
||||
if newMode == .collapse {
|
||||
expandServerDomainSet.remove(server.domain)
|
||||
} else {
|
||||
expandServerDomainSet.insert(server.domain)
|
||||
}
|
||||
|
||||
tableView?.performBatchUpdates(updates, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - SignIn methods & structs
|
||||
extension PickServerViewModel {
|
||||
enum AuthenticationError: Error, LocalizedError {
|
||||
|
|
|
@ -83,8 +83,8 @@ class PickServerCell: UITableViewCell {
|
|||
|
||||
private var expandButton: UIButton = {
|
||||
let button = UIButton(type: .custom)
|
||||
button.setTitle(L10n.Scene.ServerPicker.Button.seeMore, for: .normal)
|
||||
button.setTitle(L10n.Scene.ServerPicker.Button.seeLess, for: .selected)
|
||||
button.setTitle(L10n.Scene.ServerPicker.Button.seemore, for: .normal)
|
||||
button.setTitle(L10n.Scene.ServerPicker.Button.seeless, for: .selected)
|
||||
button.setTitleColor(Asset.Colors.lightBrandBlue.color, for: .normal)
|
||||
button.titleLabel?.font = .preferredFont(forTextStyle: .footnote)
|
||||
button.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
@ -217,7 +217,7 @@ extension PickServerCell {
|
|||
let expandButtonTopConstraintInCollapse = expandButton.topAnchor.constraint(equalTo: descriptionLabel.lastBaselineAnchor, constant: 12)
|
||||
collapseConstraints.append(expandButtonTopConstraintInCollapse)
|
||||
|
||||
let expandButtonTopConstraintInExpand = expandButton.topAnchor.constraint(equalTo: expandBox.bottomAnchor, constant: 8)
|
||||
let expandButtonTopConstraintInExpand = expandButton.topAnchor.constraint(equalTo: expandBox.bottomAnchor, constant: 8).priority(.defaultHigh)
|
||||
expandConstraints.append(expandButtonTopConstraintInExpand)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
|
@ -255,7 +255,7 @@ extension PickServerCell {
|
|||
thumbImageView.leadingAnchor.constraint(equalTo: expandBox.leadingAnchor),
|
||||
expandBox.trailingAnchor.constraint(equalTo: thumbImageView.trailingAnchor),
|
||||
thumbImageView.topAnchor.constraint(equalTo: expandBox.topAnchor),
|
||||
thumbImageView.heightAnchor.constraint(equalTo: thumbImageView.widthAnchor, multiplier: 151.0 / 303.0),
|
||||
thumbImageView.heightAnchor.constraint(equalTo: thumbImageView.widthAnchor, multiplier: 151.0 / 303.0).priority(.defaultHigh),
|
||||
|
||||
infoStackView.leadingAnchor.constraint(equalTo: expandBox.leadingAnchor),
|
||||
expandBox.trailingAnchor.constraint(equalTo: infoStackView.trailingAnchor),
|
||||
|
|
|
@ -74,9 +74,9 @@ extension PickServerCategoryView {
|
|||
guard let category = category else { return }
|
||||
titleLabel.text = category.title
|
||||
switch category {
|
||||
case .All:
|
||||
case .all:
|
||||
titleLabel.font = UIFont.systemFont(ofSize: 17)
|
||||
case .Some:
|
||||
case .some:
|
||||
titleLabel.font = UIFont.systemFont(ofSize: 28)
|
||||
}
|
||||
}
|
||||
|
@ -85,13 +85,13 @@ extension PickServerCategoryView {
|
|||
if selected {
|
||||
bgView.backgroundColor = Asset.Colors.lightBrandBlue.color
|
||||
bgView.applyShadow(color: Asset.Colors.lightBrandBlue.color, alpha: 1, x: 0, y: 0, blur: 4.0)
|
||||
if case .All = category {
|
||||
if case .all = category {
|
||||
titleLabel.textColor = Asset.Colors.lightWhite.color
|
||||
}
|
||||
} else {
|
||||
bgView.backgroundColor = Asset.Colors.lightWhite.color
|
||||
bgView.applyShadow(color: Asset.Colors.lightBrandBlue.color, alpha: 0, x: 0, y: 0, blur: 0.0)
|
||||
if case .All = category {
|
||||
if case .all = category {
|
||||
titleLabel.textColor = Asset.Colors.lightBrandBlue.color
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,18 @@
|
|||
import UIKit
|
||||
|
||||
class PrimaryActionButton: UIButton {
|
||||
|
||||
var isLoading: Bool = false
|
||||
|
||||
lazy var activityIndicator: UIActivityIndicatorView = {
|
||||
let indicator = UIActivityIndicatorView(style: .medium)
|
||||
indicator.hidesWhenStopped = true
|
||||
indicator.translatesAutoresizingMaskIntoConstraints = false
|
||||
return indicator
|
||||
}()
|
||||
|
||||
private var originalButtonTitle: String?
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
_init()
|
||||
|
@ -17,6 +29,31 @@ class PrimaryActionButton: UIButton {
|
|||
super.init(coder: coder)
|
||||
_init()
|
||||
}
|
||||
|
||||
func showLoading() {
|
||||
guard !isLoading else { return }
|
||||
isEnabled = false
|
||||
isLoading = true
|
||||
originalButtonTitle = title(for: .disabled)
|
||||
self.setTitle("", for: .disabled)
|
||||
|
||||
addSubview(activityIndicator)
|
||||
NSLayoutConstraint.activate([
|
||||
activityIndicator.centerXAnchor.constraint(equalTo: self.centerXAnchor),
|
||||
activityIndicator.centerYAnchor.constraint(equalTo: self.centerYAnchor),
|
||||
])
|
||||
activityIndicator.startAnimating()
|
||||
}
|
||||
|
||||
func stopLoading() {
|
||||
guard isLoading else { return }
|
||||
isLoading = false
|
||||
if activityIndicator.superview == self {
|
||||
activityIndicator.removeFromSuperview()
|
||||
}
|
||||
isEnabled = true
|
||||
self.setTitle(originalButtonTitle, for: .disabled)
|
||||
}
|
||||
}
|
||||
|
||||
extension PrimaryActionButton {
|
||||
|
|
|
@ -102,11 +102,11 @@ extension WelcomeViewController {
|
|||
extension WelcomeViewController {
|
||||
@objc
|
||||
private func signUpButtonDidClicked(_ sender: UIButton) {
|
||||
coordinator.present(scene: .pickServer(viewMode: PickServerViewModel(context: context, mode: .SignUp)), from: self, transition: .show)
|
||||
coordinator.present(scene: .pickServer(viewMode: PickServerViewModel(context: context, mode: .signUp)), from: self, transition: .show)
|
||||
}
|
||||
|
||||
@objc
|
||||
private func signInButtonDidClicked(_ sender: UIButton) {
|
||||
coordinator.present(scene: .pickServer(viewMode: PickServerViewModel(context: context, mode: .SignIn)), from: self, transition: .show)
|
||||
coordinator.present(scene: .pickServer(viewMode: PickServerViewModel(context: context, mode: .signIn)), from: self, transition: .show)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue