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:
parent
906b13c03d
commit
8d97b5a51e
@ -306,8 +306,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"title": "Welcome back",
|
"title": "Welcome Back",
|
||||||
"subtitle": "Log you in on the server you created your account on.",
|
"subtitle": "Log in with the server where you created your account.",
|
||||||
"server_search_field": {
|
"server_search_field": {
|
||||||
"placeholder": "Enter URL or search for your server"
|
"placeholder": "Enter URL or search for your server"
|
||||||
}
|
}
|
||||||
|
@ -306,8 +306,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"title": "Welcome back",
|
"title": "Welcome Back",
|
||||||
"subtitle": "Log you in on the server you created your account on.",
|
"subtitle": "Log in with the server where you created your account.",
|
||||||
"server_search_field": {
|
"server_search_field": {
|
||||||
"placeholder": "Enter URL or search for your server"
|
"placeholder": "Enter URL or search for your server"
|
||||||
}
|
}
|
||||||
|
@ -608,10 +608,6 @@ extension SceneCoordinator: MastodonLoginViewControllerDelegate {
|
|||||||
func backButtonPressed(_ viewController: MastodonLoginViewController) {
|
func backButtonPressed(_ viewController: MastodonLoginViewController) {
|
||||||
viewController.navigationController?.popViewController(animated: true)
|
viewController.navigationController?.popViewController(animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func nextButtonPressed(_ viewController: MastodonLoginViewController) {
|
|
||||||
viewController.login()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//MARK: - SettingsCoordinatorDelegate
|
//MARK: - SettingsCoordinatorDelegate
|
||||||
|
@ -1,12 +1,58 @@
|
|||||||
//
|
// Copyright © 2024 Mastodon gGmbH. All rights reserved.
|
||||||
// MastodonLoginServerTableViewCell.swift
|
|
||||||
// Mastodon
|
|
||||||
//
|
|
||||||
// Created by Nathan Mattes on 11.11.22.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import MastodonAsset
|
||||||
|
|
||||||
class MastodonLoginServerTableViewCell: UITableViewCell {
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,7 @@ class MastodonLoginView: UIView {
|
|||||||
tableView.backgroundColor = Asset.Scene.Onboarding.textFieldBackground.color
|
tableView.backgroundColor = Asset.Scene.Onboarding.textFieldBackground.color
|
||||||
tableView.keyboardDismissMode = .onDrag
|
tableView.keyboardDismissMode = .onDrag
|
||||||
tableView.layer.cornerRadius = 10
|
tableView.layer.cornerRadius = 10
|
||||||
|
tableView.separatorStyle = .none
|
||||||
|
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@ import MastodonLocalization
|
|||||||
|
|
||||||
protocol MastodonLoginViewControllerDelegate: AnyObject {
|
protocol MastodonLoginViewControllerDelegate: AnyObject {
|
||||||
func backButtonPressed(_ viewController: MastodonLoginViewController)
|
func backButtonPressed(_ viewController: MastodonLoginViewController)
|
||||||
func nextButtonPressed(_ viewController: MastodonLoginViewController)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MastodonLoginViewSection: Hashable {
|
enum MastodonLoginViewSection: Hashable {
|
||||||
@ -24,10 +23,6 @@ enum MastodonLoginViewSection: Hashable {
|
|||||||
|
|
||||||
class MastodonLoginViewController: UIViewController, NeedsDependency {
|
class MastodonLoginViewController: UIViewController, NeedsDependency {
|
||||||
|
|
||||||
enum RightBarButtonState {
|
|
||||||
case normal, disabled, loading
|
|
||||||
}
|
|
||||||
|
|
||||||
weak var delegate: MastodonLoginViewControllerDelegate?
|
weak var delegate: MastodonLoginViewControllerDelegate?
|
||||||
var dataSource: UITableViewDiffableDataSource<MastodonLoginViewSection, Mastodon.Entity.Server>?
|
var dataSource: UITableViewDiffableDataSource<MastodonLoginViewSection, Mastodon.Entity.Server>?
|
||||||
let viewModel: MastodonLoginViewModel
|
let viewModel: MastodonLoginViewModel
|
||||||
@ -59,20 +54,12 @@ class MastodonLoginViewController: UIViewController, NeedsDependency {
|
|||||||
override func loadView() {
|
override func loadView() {
|
||||||
let loginView = MastodonLoginView()
|
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?.target = self
|
||||||
navigationItem.leftBarButtonItem?.action = #selector(backButtonPressed(_:))
|
navigationItem.leftBarButtonItem?.action = #selector(backButtonPressed(_:))
|
||||||
|
|
||||||
loginView.searchTextField.addTarget(self, action: #selector(MastodonLoginViewController.textfieldDidChange(_:)), for: .editingChanged)
|
loginView.searchTextField.addTarget(self, action: #selector(MastodonLoginViewController.textfieldDidChange(_:)), for: .editingChanged)
|
||||||
loginView.tableView.delegate = self
|
loginView.tableView.delegate = self
|
||||||
loginView.tableView.register(MastodonLoginServerTableViewCell.self, forCellReuseIdentifier: MastodonLoginServerTableViewCell.reuseIdentifier)
|
loginView.tableView.register(MastodonLoginServerTableViewCell.self, forCellReuseIdentifier: MastodonLoginServerTableViewCell.reuseIdentifier)
|
||||||
setRightBarButtonState(.disabled)
|
|
||||||
|
|
||||||
view = loginView
|
view = loginView
|
||||||
}
|
}
|
||||||
@ -85,18 +72,20 @@ class MastodonLoginViewController: UIViewController, NeedsDependency {
|
|||||||
|
|
||||||
let dataSource = UITableViewDiffableDataSource<MastodonLoginViewSection, Mastodon.Entity.Server>(tableView: contentView.tableView) { [weak self] tableView, indexPath, itemIdentifier in
|
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,
|
guard let cell = tableView.dequeueReusableCell(withIdentifier: MastodonLoginServerTableViewCell.reuseIdentifier, for: indexPath) as? MastodonLoginServerTableViewCell,
|
||||||
let self = self else {
|
let self else {
|
||||||
fatalError("Wrong cell")
|
fatalError("Wrong cell")
|
||||||
}
|
}
|
||||||
|
|
||||||
let server = self.viewModel.filteredServers[indexPath.row]
|
let server = self.viewModel.filteredServers[indexPath.row]
|
||||||
var configuration = cell.defaultContentConfiguration()
|
let isLastServer: Bool
|
||||||
configuration.text = server.domain
|
|
||||||
|
|
||||||
cell.contentConfiguration = configuration
|
if let lastServer = self.viewModel.filteredServers.last {
|
||||||
cell.accessoryType = .disclosureIndicator
|
isLastServer = (lastServer == server)
|
||||||
|
} else {
|
||||||
|
isLastServer = false
|
||||||
|
}
|
||||||
|
|
||||||
cell.backgroundColor = Asset.Scene.Onboarding.textFieldBackground.color
|
cell.configure(domain: server.domain, separatorHidden: isLastServer)
|
||||||
|
|
||||||
return cell
|
return cell
|
||||||
}
|
}
|
||||||
@ -131,15 +120,7 @@ class MastodonLoginViewController: UIViewController, NeedsDependency {
|
|||||||
delegate?.backButtonPressed(self)
|
delegate?.backButtonPressed(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func nextButtonPressed(_ sender: Any) {
|
func login(on server: Mastodon.Entity.Server) {
|
||||||
contentView.searchTextField.resignFirstResponder()
|
|
||||||
delegate?.nextButtonPressed(self)
|
|
||||||
setRightBarButtonState(.loading)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func login() {
|
|
||||||
guard let server = viewModel.selectedServer else { return }
|
|
||||||
|
|
||||||
authenticationViewModel
|
authenticationViewModel
|
||||||
.authenticated.sink { (domain, account) in
|
.authenticated.sink { (domain, account) in
|
||||||
Task { @MainActor in
|
Task { @MainActor in
|
||||||
@ -177,9 +158,7 @@ class MastodonLoginViewController: UIViewController, NeedsDependency {
|
|||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
let alert = UIAlertController.standardAlert(of: error)
|
let alert = UIAlertController.standardAlert(of: error)
|
||||||
self.present(alert, animated: true)
|
self.present(alert, animated: true)
|
||||||
self.setRightBarButtonState(.normal)
|
|
||||||
case .finished:
|
case .finished:
|
||||||
self.setRightBarButtonState(.normal)
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
} receiveValue: { [weak self] info in
|
} receiveValue: { [weak self] info in
|
||||||
@ -204,18 +183,17 @@ class MastodonLoginViewController: UIViewController, NeedsDependency {
|
|||||||
@objc func textfieldDidChange(_ textField: UITextField) {
|
@objc func textfieldDidChange(_ textField: UITextField) {
|
||||||
viewModel.filterServers(withText: textField.text)
|
viewModel.filterServers(withText: textField.text)
|
||||||
|
|
||||||
|
|
||||||
if let text = textField.text,
|
if let text = textField.text,
|
||||||
let domain = AuthenticationViewModel.parseDomain(from: text) {
|
let domain = AuthenticationViewModel.parseDomain(from: text) {
|
||||||
|
let selectedServer = Mastodon.Entity.Server(domain: domain, instance: .init(domain: domain))
|
||||||
viewModel.selectedServer = .init(domain: domain, instance: .init(domain: domain))
|
if viewModel.filteredServers.contains(where: { $0 == selectedServer }) == false {
|
||||||
setRightBarButtonState(.normal)
|
viewModel.filteredServers.insert(selectedServer, at: 0)
|
||||||
} else {
|
|
||||||
viewModel.selectedServer = nil
|
|
||||||
setRightBarButtonState(.disabled)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
serversUpdated(viewModel)
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Notifications
|
// MARK: - Notifications
|
||||||
@objc func keyboardWillShowNotification(_ notification: Notification) {
|
@objc func keyboardWillShowNotification(_ notification: Notification) {
|
||||||
|
|
||||||
@ -239,25 +217,6 @@ class MastodonLoginViewController: UIViewController, NeedsDependency {
|
|||||||
self.view.layoutIfNeeded()
|
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
|
// MARK: - OnboardingViewControllerAppearance
|
||||||
@ -266,14 +225,10 @@ extension MastodonLoginViewController: OnboardingViewControllerAppearance { }
|
|||||||
// MARK: - UITableViewDelegate
|
// MARK: - UITableViewDelegate
|
||||||
extension MastodonLoginViewController: UITableViewDelegate {
|
extension MastodonLoginViewController: UITableViewDelegate {
|
||||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
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)
|
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)
|
snapshot.appendItems(viewModel.filteredServers)
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.dataSource?.apply(snapshot, animatingDifferences: false)
|
self.dataSource?.applySnapshotUsingReloadData(snapshot)
|
||||||
let numberOfResults = viewModel.filteredServers.count
|
let numberOfResults = viewModel.filteredServers.count
|
||||||
self.contentView.updateCorners(numberOfResults: numberOfResults)
|
self.contentView.updateCorners(numberOfResults: numberOfResults)
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ protocol MastodonLoginViewModelDelegate: AnyObject {
|
|||||||
class MastodonLoginViewModel {
|
class MastodonLoginViewModel {
|
||||||
|
|
||||||
private var serverList: [Mastodon.Entity.Server] = []
|
private var serverList: [Mastodon.Entity.Server] = []
|
||||||
var selectedServer: Mastodon.Entity.Server?
|
|
||||||
var filteredServers: [Mastodon.Entity.Server] = []
|
var filteredServers: [Mastodon.Entity.Server] = []
|
||||||
|
|
||||||
weak var appContext: AppContext?
|
weak var appContext: AppContext?
|
||||||
|
@ -863,10 +863,10 @@ public enum L10n {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public enum Login {
|
public enum Login {
|
||||||
/// Log you in on the server you created your account on.
|
/// Log in with the server where you created your account.
|
||||||
public static let subtitle = L10n.tr("Localizable", "Scene.Login.Subtitle", fallback: "Log you in on the server you created your account on.")
|
public static let subtitle = L10n.tr("Localizable", "Scene.Login.Subtitle", fallback: "Log in with the server where you created your account.")
|
||||||
/// Welcome back
|
/// Welcome Back
|
||||||
public static let title = L10n.tr("Localizable", "Scene.Login.Title", fallback: "Welcome back")
|
public static let title = L10n.tr("Localizable", "Scene.Login.Title", fallback: "Welcome Back")
|
||||||
public enum ServerSearchField {
|
public enum ServerSearchField {
|
||||||
/// Enter URL or search for your server
|
/// 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")
|
public static let placeholder = L10n.tr("Localizable", "Scene.Login.ServerSearchField.Placeholder", fallback: "Enter URL or search for your server")
|
||||||
|
@ -307,8 +307,8 @@ uploaded to Mastodon.";
|
|||||||
"Scene.HomeTimeline.TimelinePill.PostSent" = "Post Sent";
|
"Scene.HomeTimeline.TimelinePill.PostSent" = "Post Sent";
|
||||||
"Scene.HomeTimeline.Title" = "Home";
|
"Scene.HomeTimeline.Title" = "Home";
|
||||||
"Scene.Login.ServerSearchField.Placeholder" = "Enter URL or search for your server";
|
"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.Subtitle" = "Log in with the server where you created your account.";
|
||||||
"Scene.Login.Title" = "Welcome back";
|
"Scene.Login.Title" = "Welcome Back";
|
||||||
"Scene.Notification.FollowRequest.Accept" = "Accept";
|
"Scene.Notification.FollowRequest.Accept" = "Accept";
|
||||||
"Scene.Notification.FollowRequest.Accepted" = "Accepted";
|
"Scene.Notification.FollowRequest.Accepted" = "Accepted";
|
||||||
"Scene.Notification.FollowRequest.Reject" = "reject";
|
"Scene.Notification.FollowRequest.Reject" = "reject";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user