Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: authentication flow view -> Cloud password login - WPB-15222 #2455

Open
wants to merge 59 commits into
base: develop
Choose a base branch
from

Conversation

KaterinaWire
Copy link
Contributor

@KaterinaWire KaterinaWire commented Jan 29, 2025

Issue

This PR introduces 2 views for Path 1, 2 and 3, but to fit the design, changes need to be made for 2 reusable elements::
PasswordField and LabeledTextField. As a result of these changes, we need to update Snapshots.

Screenshot 2025-01-30 at 09 36 57 Screenshot 2025-01-30 at 09 37 04

Testing

Checklist

  • Title contains a reference JIRA issue number like [WPB-XXX].
  • Description is filled and free of optional paragraphs.
  • Adds/updates automated tests.

UI accessibility checklist

If your PR includes UI changes, please utilize this checklist:

  • Make sure you use the API for UI elements that support large fonts.
  • All colors are taken from WireDesign.ColorTheme or constructed using WireDesign.BaseColorPalette.
  • New UI elements have Accessibility strings for VoiceOver.

@echoes-hq echoes-hq bot added the echoes/initiative: scale Enterprise Readiness Initiatives label Jan 29, 2025
@KaterinaWire KaterinaWire marked this pull request as ready for review January 30, 2025 08:38
Copy link
Contributor

github-actions bot commented Jan 30, 2025

Test Results

  2 files   12 suites   47s ⏱️
130 tests 129 ✅ 1 💤 0 ❌
131 runs  130 ✅ 1 💤 0 ❌

Results for commit 7defe15.

♻️ This comment has been updated with latest results.

@KaterinaWire KaterinaWire requested a review from jullianm January 31, 2025 16:03
@datadog-wireapp
Copy link

datadog-wireapp bot commented Jan 31, 2025

Datadog Report

Branch report: feat/authentication-ui-cloud-password-unclaimed-v2
Commit report: 595898b
Test service: wire-ios-mono

✅ 0 Failed, 102 Passed, 1 Skipped, 17.01s Total Time

@jullianm
Copy link
Contributor

jullianm commented Feb 3, 2025

@KaterinaWire LGTM, left a few non blocking comments, also I don't see the second view ("don't have a wire account..") in the snapshots

Copy link
Contributor

@samwyndham samwyndham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!

Copy link
Contributor

@samwyndham samwyndham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work! We should probably take a look at some of our access modifiers. Most of them don't need to be public - package should be enough.

Comment on lines 29 to 30
@MainActor var accountsURL: URL { get }
@MainActor var passwordValidator: any PasswordValidator { get }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: why do these need to marked @MainActor?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't need, fixed

public let accountsURL: URL
public let passwordValidator: any PasswordValidator

init(accountsURL: URL, passwordValidator: any PasswordValidator) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: does the password validator need to be injected because it the rules to validate a password are configurable and come from the Wire-iOS project?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.
We have a protocol

public protocol PasswordValidator {
    func validate(_ password: String) -> Bool
    var localizedRulesDescription: String? { get }
}

which will be reused for export/import backup.


@ObservedObject var viewModel: LoginOrRegisterViaEmailViewModel

var body: some View {
Color.red
@State var password: String = ""
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: I wonder if this should be part of the view model?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would keep it as a private in the view.

  1. We don't need to pass password to the multiple views (as it's with email), so there is no need to store it.
  2. From the performance point of view, changing the password only updates this view, not the entire ViewModel.

}

public var body: some View {
VStack(alignment: .center, spacing: 14) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: improve readability by breaking up a large body into components like:

var body: some View {
  VStack {
    emailField
    passwordField
    submitButton
    forgotPasswordButton
  }
}

@ViewBuilder
private var emailField: some View (
  LabeledTextField(
    placeholder: nil,
    title: L10n.CloudUserLogin.InputEmail.title,
    string: .constant(viewModel.email
  )
  .disabled(true)
}

@ViewBuilder
private var passwordField: some View {
  ...
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

.disabled(!viewModel.isValidPassword(password))

Button(action: {
UIApplication.shared.open(viewModel.forgotPasswordURL)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be done in the view model:

viewModel.recoverPassword()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

func submitPassword(_ password: String) {
Task {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: run this in a detached task, otherwise it will run on the main thread and block the UI.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@ObservedObject var viewModel: LoginViaEmailViewModel

@State private var password = ""
@State var password: String = ""
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: move this to the view model. If you keep in here, it should be marked as private (SwiftUI best practice)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made it private

TextField("", text: .constant(viewModel.email))
.textFieldStyle(.roundedBorder)
.foregroundStyle(.secondary)
ScrollView {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: increase readability by breaking this up into components and using view builders.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment on lines 29 to 30
let forgotPasswordURL: URL
let passwordValidator: any PasswordValidator
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: mark everything except email private.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know I was the one to separate LoginViaEmail and LoginOrRegisterViaEmail, but i wonder if it would make sense to combine them since they are almost identical. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@johnxnguyen I would keep it separately. I see some Pros and Cons, but maybe we can keep it separately for now.
Cons:

  • duplicate code

Pros:

  • view model for LoginOrRegisterViaEmail contains additional methods, that should be nil for login without registration;
  • single responsibility;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But we will have one more similar view and will increase code duplication. I combined LoginViaEmail and LoginOrRegisterViaEmail

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
echoes/initiative: scale Enterprise Readiness Initiatives
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants