2
2
mirror of https://github.com/mastodon/mastodon-ios synced 2025-04-11 22:58:02 +02:00

"Welcome back" screen cleanup (IOS-226) (#1282)

* Update texts (IOS-226)

* Remove next-button (IOS-226)

* Tap on row to login (IOS-226)

* Make text use blurple and no disclosure indicator (IOS-226)

* Fix separator lines (IOS-226)

Well. Configurations don't work with custom UI-elements (or I'm just stupid), that's why I had to fall back to good ol UITableViewCell with UIKit-components
This commit is contained in:
Nathan Mattes 2024-05-03 20:53:20 +02:00 committed by GitHub
parent 906b13c03d
commit 8d97b5a51e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 88 additions and 91 deletions

View File

@ -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"
}

View File

@ -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"
}

View File

@ -608,10 +608,6 @@ extension SceneCoordinator: MastodonLoginViewControllerDelegate {
func backButtonPressed(_ viewController: MastodonLoginViewController) {
viewController.navigationController?.popViewController(animated: true)
}
func nextButtonPressed(_ viewController: MastodonLoginViewController) {
viewController.login()
}
}
//MARK: - SettingsCoordinatorDelegate

View File

@ -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
}
}

View File

@ -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)

View File

@ -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<MastodonLoginViewSection, Mastodon.Entity.Server>?
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<MastodonLoginViewSection, Mastodon.Entity.Server>(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)
}

View File

@ -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?

View File

@ -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")

View File

@ -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";