Skip to content

Commit 92e1453

Browse files
feat: Implement Twitter provider
1 parent a4c120d commit 92e1453

File tree

5 files changed

+130
-0
lines changed

5 files changed

+130
-0
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import FirebaseAuth
16+
import FirebaseAuthSwiftUI
17+
import FirebaseCore
18+
import SwiftUI
19+
20+
public class TwitterProviderAuthUI: AuthProviderSwift, AuthProviderUI {
21+
@MainActor public func createAuthCredential() async throws -> AuthCredential {
22+
let provider = OAuthProvider(providerID: providerId)
23+
return try await withCheckedThrowingContinuation { continuation in
24+
provider.getCredentialWith(nil) { credential, error in
25+
if let error {
26+
continuation
27+
.resume(throwing: AuthServiceError.signInFailed(underlying: error))
28+
} else if let credential {
29+
continuation.resume(returning: credential)
30+
} else {
31+
continuation
32+
.resume(throwing: AuthServiceError
33+
.invalidCredentials("Twitter did not provide a valid AuthCredential"))
34+
}
35+
}
36+
}
37+
}
38+
39+
public var provider: AuthProviderSwift { self }
40+
public let id: String = "twitter"
41+
let providerId = "twitter.com"
42+
43+
@MainActor public func authButton() -> AnyView {
44+
AnyView(SignInWithTwitterButton())
45+
}
46+
47+
// TODO: need to implement delete user protocol
48+
// @MainActor public func deleteUser(user _: User) async throws {
49+
// <#code#>
50+
// }
51+
52+
public init() {}
53+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import FirebaseAuthSwiftUI
16+
import SwiftUI
17+
18+
/// A button for signing in with Twitter/X
19+
@MainActor
20+
public struct SignInWithTwitterButton {
21+
@Environment(AuthService.self) private var authService
22+
public init() {}
23+
}
24+
25+
extension SignInWithTwitterButton: View {
26+
public var body: some View {
27+
Button(action: {
28+
// TODO: Implement Twitter sign-in action
29+
}) {
30+
Text("Sign in with Twitter")
31+
}
32+
}
33+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
@testable import FirebaseTwitterSwiftUI
16+
import Testing
17+
18+
@Test func example() async throws {
19+
// Write your test here and use APIs like `#expect(...)` to check expected conditions.
20+
}

Package.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ let package = Package(
7878
name: "FirebasePhoneAuthSwiftUI",
7979
targets: ["FirebasePhoneAuthSwiftUI"]
8080
),
81+
.library(
82+
name: "FirebaseTwitterSwiftUI",
83+
targets: ["FirebaseTwitterSwiftUI"]
84+
),
8185
],
8286
dependencies: [
8387
.package(
@@ -307,5 +311,17 @@ let package = Package(
307311
dependencies: ["FirebasePhoneAuthSwiftUI"],
308312
path: "FirebaseSwiftUI/FirebasePhoneAuthSwiftUI/Tests/"
309313
),
314+
.target(
315+
name: "FirebaseTwitterSwiftUI",
316+
dependencies: [
317+
"FirebaseAuthSwiftUI",
318+
],
319+
path: "FirebaseSwiftUI/FirebaseTwitterSwiftUI/Sources"
320+
),
321+
.testTarget(
322+
name: "FirebaseTwitterSwiftUITests",
323+
dependencies: ["FirebaseTwitterSwiftUI"],
324+
path: "FirebaseSwiftUI/FirebaseTwitterSwiftUI/Tests/"
325+
),
310326
]
311327
)

samples/swiftui/FirebaseSwiftUIExample/FirebaseSwiftUIExample.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
4600E5542DD777BE00EED5F3 /* FirebaseCore in Frameworks */ = {isa = PBXBuildFile; productRef = 4600E5532DD777BE00EED5F3 /* FirebaseCore */; };
1212
4607CC9C2D9BFE29009EC3F5 /* FirebaseAuthSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = 4607CC9B2D9BFE29009EC3F5 /* FirebaseAuthSwiftUI */; };
1313
4607CC9E2D9BFE29009EC3F5 /* FirebaseGoogleSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = 4607CC9D2D9BFE29009EC3F5 /* FirebaseGoogleSwiftUI */; };
14+
4681E0002E97F22B00387C88 /* FirebaseTwitterSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = 4681DFFF2E97F22B00387C88 /* FirebaseTwitterSwiftUI */; };
1415
46CB7B252D773F2100F1FD0A /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 46CB7B242D773F2100F1FD0A /* GoogleService-Info.plist */; };
1516
46F89C392D64B04E000F8BC0 /* FirebaseAuthSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = 46F89C382D64B04E000F8BC0 /* FirebaseAuthSwiftUI */; };
1617
46F89C4D2D64BB9B000F8BC0 /* FirebaseAuthSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = 46F89C4C2D64BB9B000F8BC0 /* FirebaseAuthSwiftUI */; };
@@ -83,6 +84,7 @@
8384
46F89C4D2D64BB9B000F8BC0 /* FirebaseAuthSwiftUI in Frameworks */,
8485
4607CC9E2D9BFE29009EC3F5 /* FirebaseGoogleSwiftUI in Frameworks */,
8586
8D808CB92DB081F900D2293F /* FirebasePhoneAuthSwiftUI in Frameworks */,
87+
4681E0002E97F22B00387C88 /* FirebaseTwitterSwiftUI in Frameworks */,
8688
4607CC9C2D9BFE29009EC3F5 /* FirebaseAuthSwiftUI in Frameworks */,
8789
);
8890
runOnlyForDeploymentPostprocessing = 0;
@@ -161,6 +163,7 @@
161163
4607CC9D2D9BFE29009EC3F5 /* FirebaseGoogleSwiftUI */,
162164
8D808CB62DB0811900D2293F /* FirebaseFacebookSwiftUI */,
163165
8D808CB82DB081F900D2293F /* FirebasePhoneAuthSwiftUI */,
166+
4681DFFF2E97F22B00387C88 /* FirebaseTwitterSwiftUI */,
164167
);
165168
productName = FirebaseSwiftUIExample;
166169
productReference = 46F89C082D64A86C000F8BC0 /* FirebaseSwiftUIExample.app */;
@@ -660,6 +663,11 @@
660663
isa = XCSwiftPackageProductDependency;
661664
productName = FirebaseGoogleSwiftUI;
662665
};
666+
4681DFFF2E97F22B00387C88 /* FirebaseTwitterSwiftUI */ = {
667+
isa = XCSwiftPackageProductDependency;
668+
package = 8D808CB52DB07EBD00D2293F /* XCLocalSwiftPackageReference "../../../../FirebaseUI-iOS" */;
669+
productName = FirebaseTwitterSwiftUI;
670+
};
663671
46F89C382D64B04E000F8BC0 /* FirebaseAuthSwiftUI */ = {
664672
isa = XCSwiftPackageProductDependency;
665673
productName = FirebaseAuthSwiftUI;

0 commit comments

Comments
 (0)