-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
WIP Add SwiftUI Quickstart for Storage #1134
base: main
Are you sure you want to change the base?
Conversation
ac7f271
to
d818aa3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great progress!
Just a few structure comments for now. I'll review the code later.
storage/Podfile
Outdated
@@ -1,7 +1,7 @@ | |||
# StorageExample | |||
|
|||
use_frameworks! | |||
platform :ios, '10.0' | |||
platform :ios, '14.4' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is 13.0 or 14.0 possible?
Also, please factor the platform spec into the targets so we can keep 10.0 for the old quickstart.
@@ -11,6 +11,8 @@ | |||
1073487D20333C27004A66D1 /* StorageExampleUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1073487C20333C27004A66D1 /* StorageExampleUITests.m */; }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Run pod deintegrate
before merging to keep the Xcode project more easily mergeable and able to support Swift PM.
@@ -0,0 +1,77 @@ | |||
// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this repo isn't consistent with this, but please use the standard Firebase open source copyright like https://github.com/firebase/firebase-ios-sdk/blob/master/FirebaseStorageSwift/Sources/SwiftAPIExtension.swift#L1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome job– this is great! 🥳
Some additional suggestions/tips:
- add the
Image.xcassets
to the new app’s target so the new app picks up the standard qs icon - use SFSymbols when possible
- check out Apple's Human Interface Guidelines (if you'd like more design inspo, Im happy to share some apps I refer to for their design)
- provide a screenshot of the latest UI to the PR (I should have done this when I helped make some qs 😅 )
I helped implement qs for Auth, Remote Config, and Analytics last summer. They are in UIKit but could be helpful in with design, etc. I tried to make use of the Firebase APIs clear and copy-and-paste-able by simplifying and abstracting the other stuff away.
Some examples of areas where I tried to make Firebase API usage really clear:
• AuthViewController
• ConfigViewController
All that to say, I think the usage of Firebase APIs is really clear here. I just think this is the ultimate goal for all the qs!
Sorry, there’s a lot of comments but my hope is that they are helpful. Again, great job so far!! Feel free to ping me if you have questions/want me to try and demo one/etc
p.s. i cloned your fork to have a look around. feel free branch off of the main repo if that is any easier for you 🙂
Auth.auth().signInAnonymously(completion: { (authResult, error) in | ||
if let error = error { | ||
print("Failed to sign in: \(error.localizedDescription)") | ||
} | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional refactor: use a trailing closure
Auth.auth().signInAnonymously { authResult, error in
if let error = error {
print("Failed to sign in: \(error.localizedDescription)")
}
}
struct StorageExampleSwiftUIApp: App { | ||
init() { | ||
FirebaseApp.configure() | ||
if Auth.auth().currentUser == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not suggesting a change, just making a note here.
This might be a good example to one day update with an Auth+Combine solution. Like instead of having this logic here, subscribing to an auth publisher and handing the app's evolving login states in some coordinator object that subscribes to the auth publisher.
Does this sound like a good use case for the Auth+Combine work that's underway? @peterfriese
}() | ||
|
||
public init(withStorage storage: Storage) { | ||
self.storage = storage |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I think Swift's design guidelines prefer to avoid having init methods that form a phrase. From here
So instead, something like:
public init(storage: Storage) { ... }
} | ||
|
||
func downloadImage() { | ||
UserDefaults.standard.synchronize() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think synchronize()
might not need to get called at all these days. See here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting. I will fix that.
guard let imagePath = UserDefaults.standard.string(forKey: self.photoStore.imagePathKey) else { return } | ||
self.photoStore.downloadImage(atPath: imagePath) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
optional refactor:
if let imagePath = UserDefaults.standard.string(forKey: self.photoStore.imagePathKey) {
self.photoStore.downloadImage(atPath: imagePath)
}
Suggesting because it looks like we only do one thing after the guard statement and the style script might make line 69 look odd if it truncates it for being over the maximum char length
if self.source == .camera { | ||
imagePicker.sourceType = .camera | ||
imagePicker.cameraCaptureMode = .photo | ||
} else { | ||
imagePicker.sourceType = .photoLibrary | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
optional: Since source
is an enum, could do a switch case here
} | ||
} | ||
|
||
extension ImagePickerRepresentable.Coordinator: UIImagePickerControllerDelegate { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you haven't considered it, check out PHPickerViewController
as well. There's a cool WWDC 2020 video where I learned about it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ive read a few cool articles about it. like this this one
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @ncooke3, I really wanted to use it too haha. I started with the PHPickerViewController. I got it working but I found two issues:
-
PHPickerViewController does not provide any access to the camera yet, so I was forced to also incorporate UIImagePickerController or get a camera manually.
-
There is a bug I found when using search in the PHPickerViewController and SwiftUI on an actual device. On my iPhone 12 Pro Max, the picker view process crashes whenever using the search bar. The rest of the controller behaves as usual. I opened feedback with Apple to address it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didnt know that but that's good to know! 👍
.navigationTitle("Firebase Storage") | ||
.toolbar { | ||
ToolbarItemGroup(placement: .bottomBar) { | ||
if !showUploadMenu { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: maybe refactor so it's:
if showUploadMenu {
// ...
} else {
// !showUploadMenu related logic
}
Button("❌") { | ||
showUploadMenu = false | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use sfsymbols in conjunction with the Button API to make some really clean looking buttons
Button(action: {
showUploadMenu = false
}, label: {
Image(systemName: "xmark.circle.fill")
})
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ncooke3 Absolutely. This was a temporary fix for the selector. I was hoping to incorporate something a little more exciting and maybe some animation here.
import SwiftUI | ||
import Firebase | ||
|
||
struct ImagePickerRepresentable { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice job with what you have going on this file. 👏 hopefully Apple provides us with a standard PhotoPicker
view that saves us from having to do all of this 🤞
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you. Maybe there will be something announced in June. It really seems like SwiftUI was a second class citizen for the new photo APIs, so I expect them to fix that.
d818aa3
to
b3a1d88
Compare
b3a1d88
to
e05a887
Compare
This is an incomplete migration of the Storage Quickstart to Swift UI. It is an active work in-progress.
To Do