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

[local_auth_darwin] - Converts implementation to Swift #7586

Draft
wants to merge 63 commits into
base: main
Choose a base branch
from

Conversation

Mairramer
Copy link
Contributor

@Mairramer Mairramer commented Sep 5, 2024

Part of flutter/flutter#119015
Closes flutter/flutter#119104

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@Mairramer Mairramer closed this Oct 19, 2024
@Mairramer Mairramer reopened this Nov 6, 2024
# Conflicts:
#	packages/local_auth/local_auth_darwin/darwin/local_auth_darwin/Sources/local_auth_darwin/include/local_auth_darwin/messages.g.h
#	packages/local_auth/local_auth_darwin/darwin/local_auth_darwin/Sources/local_auth_darwin/messages.g.m
@stuartmorgan
Copy link
Contributor

As a high-level comment on my specific comments above: as discussed earlier, the goal of a Swift conversion PR should be to convert the existing logic to Swift as directly as possible, modulo any language-specific idiomatic differences. A conversion is already a relatively high-risk change due to the magnitude of code being changed; intentionally mixing in refactors, subjective changes to implementation approach, etc. is highly undesirable in such a PR because it increases the risk even futher.

Any delta between the Obj-C logic and the Swift logic in this PR should be clearly and directly attributable to a language-specific reason.

If you have subjective disagreements about how the code is currently structured, please feel free to either make prequel PRs or follow-up PRs that make those changes, so they can be discussed, reviewed, and tested in isolation, rather than as part of a complete rewrite of the code.

@Mairramer
Copy link
Contributor Author

As a high-level comment on my specific comments above: as discussed earlier, the goal of a Swift conversion PR should be to convert the existing logic to Swift as directly as possible, modulo any language-specific idiomatic differences. A conversion is already a relatively high-risk change due to the magnitude of code being changed; intentionally mixing in refactors, subjective changes to implementation approach, etc. is highly undesirable in such a PR because it increases the risk even futher.

Any delta between the Obj-C logic and the Swift logic in this PR should be clearly and directly attributable to a language-specific reason.

If you have subjective disagreements about how the code is currently structured, please feel free to either make prequel PRs or follow-up PRs that make those changes, so they can be discussed, reviewed, and tested in isolation, rather than as part of a complete rewrite of the code.

I am reworking some parts you mentioned again and trying to keep the test mocks as close as possible to how they were before. There are many things I would like to remove, like the factory. While I understand the reasoning behind its use, it's not something I personally prefer. I'm working on this more slowly because I have limited time to dedicate to it.

@stuartmorgan
Copy link
Contributor

There are many things I would like to remove, like the factory. While I understand the reasoning behind its use, it's not something I personally prefer.

As I said in my previous comment:

If you have subjective disagreements about how the code is currently structured, please feel free to either make prequel PRs or follow-up PRs that make those changes, so they can be discussed, reviewed, and tested in isolation, rather than as part of a complete rewrite of the code.

This PR is not the place to make structural changes that are based on your personal preferences.

@Mairramer
Copy link
Contributor Author

@stuartmorgan I made some adjustments and I'm closer to the Objective-C implementation. There are still a few things left to be done, and if you think it's appropriate, I can mark this PR as a draft and continue working on the remaining details

// TODO(stuartmorgan): Fix this; this was the pre-Pigeon-migration
// behavior, so is preserved as part of the migration, but a failed
// authentication should return failure, not an error that results in a
// PlatformException.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm still seeing it as removed.

extension UIAlertController: AlertController {
// TODO(Mairramer): Investigate if this can be removed once the issue is fixed.
// Workaround for an issue with window hierarchy during the migration from Objective-C to Swift.
// The window hierarchy is not always properly maintained after the migration, which can lead to
Copy link
Contributor

Choose a reason for hiding this comment

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

What does this mean exactly? The plugin should not be mutating the view hierarchy.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For some reason, this is happening. Before I went on vacation, I was looking into this.

open override func present(
_ presentingViewController: UIViewController, animated: Bool, completion: (() -> Void)?
) {
DispatchQueue.main.async {
Copy link
Contributor

Choose a reason for hiding this comment

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

If there is code running on an non-main thread that wants to show an alert, that should be handled at the call site, not abstracted away in an extension.

// TODO(Mairramer): Check if is possible to remove the dispatch queue, and use the @MainActor annotation instead.
func createAlert() -> Alert {
var alert: Alert!
DispatchQueue.main.sync {
Copy link
Contributor

Choose a reason for hiding this comment

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

Same comment here. We certainly shouldn't be changing threading behavior in code that's not unit-testable. The Obj-C versions of the default implementations were, by explicit design, direct passthroughs to the underlying class, and that should be true for Swift as well.


#if os(macOS)
var view: NSView {
// TODO(Mairramer): Migrate check if is possible to remove the dispatch queue, and use the @MainActor annotation instead.
Copy link
Contributor

Choose a reason for hiding this comment

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

As in the other comments, the default implementation needs to be a direct passthrough, not containing complexities like threading logic that can't be unit tested.

What is the problem this is here to solve?

LAError.passcodeNotSet.rawValue,
LAError.authenticationFailed.rawValue:
handleError(authError: error, options: options, strings: strings, completion: completion)
return
Copy link
Contributor

Choose a reason for hiding this comment

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

Since Swift doesn't support implicit fallthrough in switch statments, aren't these returns redundant?

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, you're correct!

)
return
default:
result = .failure
Copy link
Contributor

Choose a reason for hiding this comment

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

Why have you changed the logic from returning .errorNotAvailable as the default to returning .failure as the default?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If I'm not mistaken, it was to establish a success/failure pattern and also, if I recall correctly, to avoid an exception(PlataformException) on the Dart side. (I really need to remember).

completion: @escaping (Result<AuthResultDetails, Error>) -> Void
) {
#if os(macOS)
DispatchQueue.main.async {
Copy link
Contributor

Choose a reason for hiding this comment

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

Are there cases where we are calling showAlert from non-main threads? If so, this should be outside the OS-level switch. If not, we shouldn't need this.

@@ -1,5 +1,6 @@
## NEXT
## 1.4.3
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's make this a minor version bump since it's a full rewrite, even though we don't intend any behavioral changes.

error = thrownError
} catch {
XCTFail("Unexpected error thrown: \(error)")
}
XCTAssertNil(error)
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe XCTAssertThrowsError is the standard pattern for testing throwing in Swift (applies throughout the file).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

XCTAssertThrowsError is indeed the standard when you want to test if a function throws an error, but in this case, since we have a Result, it’s also common. It depends more on whether we want to capture that error.

@Mairramer
Copy link
Contributor Author

Sorry for the delay (1 month away from code).

@Mairramer Mairramer marked this pull request as draft January 29, 2025 19:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[local_auth] iOS Swift migration
3 participants