diff --git a/Localization/StringsConvertor/input/Base.lproj/app.json b/Localization/StringsConvertor/input/Base.lproj/app.json index c54b4f821..7b102d5a0 100644 --- a/Localization/StringsConvertor/input/Base.lproj/app.json +++ b/Localization/StringsConvertor/input/Base.lproj/app.json @@ -306,8 +306,8 @@ } }, "login": { - "title": "Welcome back", - "subtitle": "Log you in on the server you created your account on.", + "title": "Welcome Back", + "subtitle": "Log in with the server where you created your account.", "server_search_field": { "placeholder": "Enter URL or search for your server" } diff --git a/Localization/app.json b/Localization/app.json index c54b4f821..7b102d5a0 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -306,8 +306,8 @@ } }, "login": { - "title": "Welcome back", - "subtitle": "Log you in on the server you created your account on.", + "title": "Welcome Back", + "subtitle": "Log in with the server where you created your account.", "server_search_field": { "placeholder": "Enter URL or search for your server" } diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index 3bd441c03..7259f6540 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -608,10 +608,6 @@ extension SceneCoordinator: MastodonLoginViewControllerDelegate { func backButtonPressed(_ viewController: MastodonLoginViewController) { viewController.navigationController?.popViewController(animated: true) } - - func nextButtonPressed(_ viewController: MastodonLoginViewController) { - viewController.login() - } } //MARK: - SettingsCoordinatorDelegate diff --git a/Mastodon/Scene/Onboarding/Login/MastodonLoginServerTableViewCell.swift b/Mastodon/Scene/Onboarding/Login/MastodonLoginServerTableViewCell.swift index 2fb599015..91ea28808 100644 --- a/Mastodon/Scene/Onboarding/Login/MastodonLoginServerTableViewCell.swift +++ b/Mastodon/Scene/Onboarding/Login/MastodonLoginServerTableViewCell.swift @@ -1,12 +1,58 @@ -// -// MastodonLoginServerTableViewCell.swift -// Mastodon -// -// Created by Nathan Mattes on 11.11.22. -// +// Copyright © 2024 Mastodon gGmbH. All rights reserved. import UIKit +import MastodonAsset class MastodonLoginServerTableViewCell: UITableViewCell { - static let reuseIdentifier = "MastodonLoginServerTableViewCell" + static let reuseIdentifier = "MastodonLoginServerTableViewCell" + + let separator: UIView + let titleLabel: UILabel + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + + separator = UIView.separatorLine + separator.translatesAutoresizingMaskIntoConstraints = false + + titleLabel = UILabel() + titleLabel.translatesAutoresizingMaskIntoConstraints = false + titleLabel.textColor = Asset.Colors.Brand.blurple.color + + super.init(style: style, reuseIdentifier: reuseIdentifier) + + backgroundColor = Asset.Scene.Onboarding.textFieldBackground.color + + contentView.addSubview(titleLabel) + contentView.addSubview(separator) + setupConstraints() + } + + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } + + override func prepareForReuse() { + titleLabel.text = nil + } + + private func setupConstraints() { + let separatorHeight = UIView.separatorLineHeight(of: contentView) + let constraints = [ + separator.heightAnchor.constraint(equalToConstant: separatorHeight), + + separator.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 18), + contentView.trailingAnchor.constraint(equalTo: separator.trailingAnchor), + contentView.bottomAnchor.constraint(equalTo: separator.bottomAnchor), + + titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 14), + titleLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16), + contentView.trailingAnchor.constraint(equalTo: titleLabel.trailingAnchor), + separator.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 13), + ] + + NSLayoutConstraint.activate(constraints) + } + + public func configure(domain: String, separatorHidden: Bool = false) { + titleLabel.text = domain + separator.isHidden = separatorHidden + } } diff --git a/Mastodon/Scene/Onboarding/Login/MastodonLoginView.swift b/Mastodon/Scene/Onboarding/Login/MastodonLoginView.swift index e71890409..d3a469eab 100644 --- a/Mastodon/Scene/Onboarding/Login/MastodonLoginView.swift +++ b/Mastodon/Scene/Onboarding/Login/MastodonLoginView.swift @@ -61,6 +61,7 @@ class MastodonLoginView: UIView { tableView.backgroundColor = Asset.Scene.Onboarding.textFieldBackground.color tableView.keyboardDismissMode = .onDrag tableView.layer.cornerRadius = 10 + tableView.separatorStyle = .none super.init(frame: frame) diff --git a/Mastodon/Scene/Onboarding/Login/MastodonLoginViewController.swift b/Mastodon/Scene/Onboarding/Login/MastodonLoginViewController.swift index fc35c6f83..50ce70ff6 100644 --- a/Mastodon/Scene/Onboarding/Login/MastodonLoginViewController.swift +++ b/Mastodon/Scene/Onboarding/Login/MastodonLoginViewController.swift @@ -15,7 +15,6 @@ import MastodonLocalization protocol MastodonLoginViewControllerDelegate: AnyObject { func backButtonPressed(_ viewController: MastodonLoginViewController) - func nextButtonPressed(_ viewController: MastodonLoginViewController) } enum MastodonLoginViewSection: Hashable { @@ -24,10 +23,6 @@ enum MastodonLoginViewSection: Hashable { class MastodonLoginViewController: UIViewController, NeedsDependency { - enum RightBarButtonState { - case normal, disabled, loading - } - weak var delegate: MastodonLoginViewControllerDelegate? var dataSource: UITableViewDiffableDataSource? let viewModel: MastodonLoginViewModel @@ -59,21 +54,13 @@ class MastodonLoginViewController: UIViewController, NeedsDependency { override func loadView() { let loginView = MastodonLoginView() - navigationItem.rightBarButtonItem = UIBarButtonItem( - title: L10n.Common.Controls.Actions.next, - style: .plain, - target: self, - action: #selector(nextButtonPressed(_:)) - ) - navigationItem.leftBarButtonItem?.target = self navigationItem.leftBarButtonItem?.action = #selector(backButtonPressed(_:)) loginView.searchTextField.addTarget(self, action: #selector(MastodonLoginViewController.textfieldDidChange(_:)), for: .editingChanged) loginView.tableView.delegate = self loginView.tableView.register(MastodonLoginServerTableViewCell.self, forCellReuseIdentifier: MastodonLoginServerTableViewCell.reuseIdentifier) - setRightBarButtonState(.disabled) - + view = loginView } @@ -85,22 +72,24 @@ class MastodonLoginViewController: UIViewController, NeedsDependency { let dataSource = UITableViewDiffableDataSource(tableView: contentView.tableView) { [weak self] tableView, indexPath, itemIdentifier in guard let cell = tableView.dequeueReusableCell(withIdentifier: MastodonLoginServerTableViewCell.reuseIdentifier, for: indexPath) as? MastodonLoginServerTableViewCell, - let self = self else { + let self else { fatalError("Wrong cell") } let server = self.viewModel.filteredServers[indexPath.row] - var configuration = cell.defaultContentConfiguration() - configuration.text = server.domain - - cell.contentConfiguration = configuration - cell.accessoryType = .disclosureIndicator - - cell.backgroundColor = Asset.Scene.Onboarding.textFieldBackground.color + let isLastServer: Bool + + if let lastServer = self.viewModel.filteredServers.last { + isLastServer = (lastServer == server) + } else { + isLastServer = false + } + cell.configure(domain: server.domain, separatorHidden: isLastServer) + return cell } - + contentView.tableView.dataSource = dataSource self.dataSource = dataSource @@ -131,15 +120,7 @@ class MastodonLoginViewController: UIViewController, NeedsDependency { delegate?.backButtonPressed(self) } - @objc func nextButtonPressed(_ sender: Any) { - contentView.searchTextField.resignFirstResponder() - delegate?.nextButtonPressed(self) - setRightBarButtonState(.loading) - } - - @objc func login() { - guard let server = viewModel.selectedServer else { return } - + func login(on server: Mastodon.Entity.Server) { authenticationViewModel .authenticated.sink { (domain, account) in Task { @MainActor in @@ -177,9 +158,7 @@ class MastodonLoginViewController: UIViewController, NeedsDependency { case .failure(let error): let alert = UIAlertController.standardAlert(of: error) self.present(alert, animated: true) - self.setRightBarButtonState(.normal) case .finished: - self.setRightBarButtonState(.normal) break } } receiveValue: { [weak self] info in @@ -203,17 +182,16 @@ class MastodonLoginViewController: UIViewController, NeedsDependency { @objc func textfieldDidChange(_ textField: UITextField) { viewModel.filterServers(withText: textField.text) - - + if let text = textField.text, let domain = AuthenticationViewModel.parseDomain(from: text) { - - viewModel.selectedServer = .init(domain: domain, instance: .init(domain: domain)) - setRightBarButtonState(.normal) - } else { - viewModel.selectedServer = nil - setRightBarButtonState(.disabled) + let selectedServer = Mastodon.Entity.Server(domain: domain, instance: .init(domain: domain)) + if viewModel.filteredServers.contains(where: { $0 == selectedServer }) == false { + viewModel.filteredServers.insert(selectedServer, at: 0) + } } + + serversUpdated(viewModel) } // MARK: - Notifications @@ -239,25 +217,6 @@ class MastodonLoginViewController: UIViewController, NeedsDependency { self.view.layoutIfNeeded() } } - - private func setRightBarButtonState(_ state: RightBarButtonState) { - switch state { - case .normal: - navigationItem.rightBarButtonItem = UIBarButtonItem( - title: L10n.Common.Controls.Actions.next, - style: .plain, - target: self, - action: #selector(nextButtonPressed(_:)) - ) - case .disabled: - navigationItem.rightBarButtonItem?.isEnabled = false - case .loading: - let activityIndicator = UIActivityIndicatorView(style: .medium) - activityIndicator.startAnimating() - let barButtonItem = UIBarButtonItem(customView: activityIndicator) - navigationItem.rightBarButtonItem = barButtonItem - } - } } // MARK: - OnboardingViewControllerAppearance @@ -266,14 +225,10 @@ extension MastodonLoginViewController: OnboardingViewControllerAppearance { } // MARK: - UITableViewDelegate extension MastodonLoginViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let server = viewModel.filteredServers[indexPath.row] - viewModel.selectedServer = server - - contentView.searchTextField.text = server.domain - viewModel.filterServers(withText: " ") - - setRightBarButtonState(.normal) tableView.deselectRow(at: indexPath, animated: true) + + let selectedServer = viewModel.filteredServers[indexPath.row] + login(on: selectedServer) } } @@ -286,7 +241,7 @@ extension MastodonLoginViewController: MastodonLoginViewModelDelegate { snapshot.appendItems(viewModel.filteredServers) DispatchQueue.main.async { - self.dataSource?.apply(snapshot, animatingDifferences: false) + self.dataSource?.applySnapshotUsingReloadData(snapshot) let numberOfResults = viewModel.filteredServers.count self.contentView.updateCorners(numberOfResults: numberOfResults) } diff --git a/Mastodon/Scene/Onboarding/Login/MastodonLoginViewModel.swift b/Mastodon/Scene/Onboarding/Login/MastodonLoginViewModel.swift index 52adcad4a..64237d71f 100644 --- a/Mastodon/Scene/Onboarding/Login/MastodonLoginViewModel.swift +++ b/Mastodon/Scene/Onboarding/Login/MastodonLoginViewModel.swift @@ -17,7 +17,6 @@ protocol MastodonLoginViewModelDelegate: AnyObject { class MastodonLoginViewModel { private var serverList: [Mastodon.Entity.Server] = [] - var selectedServer: Mastodon.Entity.Server? var filteredServers: [Mastodon.Entity.Server] = [] weak var appContext: AppContext? diff --git a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift index 877174a02..d861fccb4 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift +++ b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift @@ -863,10 +863,10 @@ public enum L10n { } } public enum Login { - /// Log you in on the server you created your account on. - public static let subtitle = L10n.tr("Localizable", "Scene.Login.Subtitle", fallback: "Log you in on the server you created your account on.") - /// Welcome back - public static let title = L10n.tr("Localizable", "Scene.Login.Title", fallback: "Welcome back") + /// Log in with the server where you created your account. + public static let subtitle = L10n.tr("Localizable", "Scene.Login.Subtitle", fallback: "Log in with the server where you created your account.") + /// Welcome Back + public static let title = L10n.tr("Localizable", "Scene.Login.Title", fallback: "Welcome Back") public enum ServerSearchField { /// Enter URL or search for your server public static let placeholder = L10n.tr("Localizable", "Scene.Login.ServerSearchField.Placeholder", fallback: "Enter URL or search for your server") diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.strings index cbc90e3fd..0c9d5f3a7 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.strings @@ -307,8 +307,8 @@ uploaded to Mastodon."; "Scene.HomeTimeline.TimelinePill.PostSent" = "Post Sent"; "Scene.HomeTimeline.Title" = "Home"; "Scene.Login.ServerSearchField.Placeholder" = "Enter URL or search for your server"; -"Scene.Login.Subtitle" = "Log you in on the server you created your account on."; -"Scene.Login.Title" = "Welcome back"; +"Scene.Login.Subtitle" = "Log in with the server where you created your account."; +"Scene.Login.Title" = "Welcome Back"; "Scene.Notification.FollowRequest.Accept" = "Accept"; "Scene.Notification.FollowRequest.Accepted" = "Accepted"; "Scene.Notification.FollowRequest.Reject" = "reject";