Skip to content

Commit

Permalink
#40: Add login screen from EI.
Browse files Browse the repository at this point in the history
- Remove SSO and replace fallback with OIDC.
  • Loading branch information
pixlwave committed Jun 27, 2022
1 parent 36c3450 commit f4dc6de
Show file tree
Hide file tree
Showing 34 changed files with 1,145 additions and 416 deletions.
126 changes: 69 additions & 57 deletions ElementX.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,11 @@
"settings_timeline_style" = "Timeline Style";
"room_timeline_style_plain_long_description" = "Plain Timeline";
"room_timeline_style_bubbled_long_description" = "Bubbled Timeline";

// MARK: - Authentication

"authentication_login_title" = "Welcome back!";
"authentication_login_forgot_password" = "Forgot password";

"authentication_server_info_title" = "Choose your server to store your data";
"authentication_server_info_matrix_description" = "Join millions for free on the largest public server";
3 changes: 3 additions & 0 deletions ElementX/Sources/BuildSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
import Foundation

final class BuildSettings {

// MARK: - Servers
static let defaultHomeserverURLString = "https://matrix.org"

// MARK: - Bug report
static let bugReportServiceBaseUrlString = "https://riot.im/bugreports"
Expand Down
8 changes: 8 additions & 0 deletions ElementX/Sources/Generated/Strings+Untranslated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ import Foundation
// swiftlint:disable explicit_type_interface function_parameter_count identifier_name line_length
// swiftlint:disable nesting type_body_length type_name vertical_whitespace_opening_braces
extension ElementL10n {
/// Forgot password
public static let authenticationLoginForgotPassword = ElementL10n.tr("Untranslated", "authentication_login_forgot_password")
/// Welcome back!
public static let authenticationLoginTitle = ElementL10n.tr("Untranslated", "authentication_login_title")
/// Join millions for free on the largest public server
public static let authenticationServerInfoMatrixDescription = ElementL10n.tr("Untranslated", "authentication_server_info_matrix_description")
/// Choose your server to store your data
public static let authenticationServerInfoTitle = ElementL10n.tr("Untranslated", "authentication_server_info_title")
/// Bubbled Timeline
public static let roomTimelineStyleBubbledLongDescription = ElementL10n.tr("Untranslated", "room_timeline_style_bubbled_long_description")
/// Plain Timeline
Expand Down
19 changes: 19 additions & 0 deletions ElementX/Sources/Other/Logging/MXLog.swift
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,25 @@ private var logger: SwiftyBeaver.Type = {
logger.error(message, file, function, line: line)
}

public static func failure(_ message: @autoclosure () -> Any, _
file: String = #file,
_ function: String = #function,
line: Int = #line,
context: Any? = nil) {
logger.error(message(), file, function, line: line, context: context)
#if DEBUG
assertionFailure("\(message())")
#endif
}

@available(swift, obsoleted: 5.4)
@objc public static func logFailure(_ message: String, file: String, function: String, line: Int) {
logger.error(message, file, function, line: line)
#if DEBUG
assertionFailure(message)
#endif
}

// MARK: - Private

fileprivate static func configureLogger(_ logger: SwiftyBeaver.Type, withConfiguration configuration: MXLogConfiguration) {
Expand Down
87 changes: 87 additions & 0 deletions ElementX/Sources/Other/SwiftUI/ErrorHandling/AlertInfo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import SwiftUI

/// A type that describes an alert to be shown to the user.
///
/// The alert info can be added to the view state bindings and used as an alert's `item`:
/// ```
/// MyView
/// .alert(item: $viewModel.alertInfo) { $0.alert }
/// ```
struct AlertInfo<T: Hashable>: Identifiable {
/// An identifier that can be used to distinguish one error from another.
let id: T
/// The alert's title.
let title: String
/// The alert's message (optional).
var message: String?
/// The alert's primary button title and action. Defaults to an Ok button with no action.
var primaryButton: (title: String, action: (() -> Void)?) = (ElementL10n.ok, nil)
/// The alert's secondary button title and action.
var secondaryButton: (title: String, action: (() -> Void)?)?
}

#warning("Remove the NSError extensions?")
extension AlertInfo {
/// Initialises the type with the title and message from an `NSError` along with the default Ok button.
init?(error: NSError? = nil) where T == Int {
self.init(id: error?.code ?? -1, error: error)
}

/// Initialises the type with the title and message from an `NSError` along with the default Ok button.
/// - Parameters:
/// - id: An ID that identifies the error.
/// - error: The Error that occurred.
init?(id: T, error: NSError? = nil) {
guard error?.domain != NSURLErrorDomain && error?.code != NSURLErrorCancelled else { return nil }

self.id = id
title = error?.userInfo[NSLocalizedFailureReasonErrorKey] as? String ?? ElementL10n.dialogTitleError
message = error?.userInfo[NSLocalizedDescriptionKey] as? String ?? ElementL10n.unknownError
}
}

extension AlertInfo {
private var messageText: Text? {
guard let message = message else { return nil }
return Text(message)
}

/// Returns a SwiftUI `Alert` created from this alert info, using default button
/// styles for both primary and (if set) secondary buttons.
var alert: Alert {
if let secondaryButton = secondaryButton {
return Alert(title: Text(title),
message: messageText,
primaryButton: alertButton(for: primaryButton),
secondaryButton: alertButton(for: secondaryButton))
} else {
return Alert(title: Text(title),
message: messageText,
dismissButton: alertButton(for: primaryButton))
}
}

private func alertButton(for buttonParameters: (title: String, action: (() -> Void)?)) -> Alert.Button {
guard let action = buttonParameters.action else {
return .default(Text(buttonParameters.title))
}

return .default(Text(buttonParameters.title), action: action)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,14 @@ final class LabelledActivityIndicatorView: UIView {
static let padding = UIEdgeInsets(top: 20, left: 40, bottom: 15, right: 40)
static let activityIndicatorScale = CGFloat(1.5)
static let cornerRadius: CGFloat = 12.0
static let stackBackgroundOpacity: CGFloat = 0.9
static let stackSpacing: CGFloat = 15
static let backgroundOpacity: CGFloat = 0.5
}

private let stackBackgroundView: UIView = {
let view = UIView()
let view = UIVisualEffectView(effect: UIBlurEffect(style: .systemMaterial))
view.layer.cornerRadius = Constants.cornerRadius
view.alpha = Constants.stackBackgroundOpacity
view.backgroundColor = .gray.withAlphaComponent(0.75)
view.clipsToBounds = true
return view
}()

Expand Down Expand Up @@ -67,6 +65,7 @@ final class LabelledActivityIndicatorView: UIView {
private func setup(text: String) {
setupStackView()
label.text = text
label.textColor = .element.primaryContent
}

private func setupStackView() {
Expand Down
21 changes: 18 additions & 3 deletions ElementX/Sources/Other/UserIndicators/RoundedToastView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,27 @@ class RoundedToastView: UIView {

private func setup(viewState: ToastViewState) {

backgroundColor = .gray.withAlphaComponent(0.75)
backgroundColor = .clear
clipsToBounds = true

setupBackgroundMaterial()
setupStackView()
stackView.addArrangedSubview(toastView(for: viewState.style))
stackView.addArrangedSubview(label)
label.text = viewState.label
label.textColor = .element.primaryContent
}

private func setupBackgroundMaterial() {
let material = UIVisualEffectView(effect: UIBlurEffect(style: .systemMaterial))
addSubview(material)
material.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
material.topAnchor.constraint(equalTo: topAnchor),
material.bottomAnchor.constraint(equalTo: bottomAnchor),
material.leadingAnchor.constraint(equalTo: leadingAnchor),
material.trailingAnchor.constraint(equalTo: trailingAnchor)
])
}

private func setupStackView() {
Expand All @@ -101,10 +116,10 @@ class RoundedToastView: UIView {
case .loading:
return activityIndicator
case .success:
imageView.image = UIImage(systemName: "checkmark.circle")
imageView.image = UIImage(systemName: "checkmark")
return imageView
case .error:
imageView.image = UIImage(systemName: "x.circle")
imageView.image = UIImage(systemName: "xmark")
return imageView
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,6 @@ class AuthenticationCoordinator: Coordinator {
switch action {
case .login:
self.showLoginScreen()
case .register:
fatalError("Not implemented")
}
}

Expand All @@ -69,18 +67,19 @@ class AuthenticationCoordinator: Coordinator {
}

private func showLoginScreen() {
let parameters = LoginScreenCoordinatorParameters()
let coordinator = LoginScreenCoordinator(parameters: parameters)
let homeserver = LoginHomeserver(address: BuildSettings.defaultHomeserverURLString)
let parameters = LoginCoordinatorParameters(navigationRouter: navigationRouter, homeserver: homeserver)
let coordinator = LoginCoordinator(parameters: parameters)

coordinator.callback = { [weak self, weak coordinator] action in
guard let self = self, let coordinator = coordinator else {
return
}

switch action {
case .login(let result):
case .login(let username, let password):
Task {
switch await self.login(username: result.username, password: result.password) {
switch await self.login(username: username, password: password) {
case .success(let userSession):
self.delegate?.authenticationCoordinator(self, didLoginWithSession: userSession)
self.remove(childCoordinator: coordinator)
Expand All @@ -90,6 +89,8 @@ class AuthenticationCoordinator: Coordinator {
MXLog.error("Failed logging in user with error: \(error)")
}
}
case .continueWithOIDC:
break
}
}

Expand Down
Loading

0 comments on commit f4dc6de

Please sign in to comment.