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

WIP Add SwiftUI Quickstart for Storage #1134

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

codeblooded
Copy link

@codeblooded codeblooded commented Mar 26, 2021

This is an incomplete migration of the Storage Quickstart to Swift UI. It is an active work in-progress.

To Do

  • Add helpful comments
  • Consider moving some state into the environment
  • Add error dialogs to UI
  • Spice it up with some styling and animation
  • Consider support for multiple images
  • Move to Swift target, replacing UIKit example

Copy link
Member

@paulb777 paulb777 left a 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'
Copy link
Member

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 */; };
Copy link
Member

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 @@
//
Copy link
Member

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

Copy link
Member

@ncooke3 ncooke3 left a 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 🙂

Comment on lines 17 to 27
Auth.auth().signInAnonymously(completion: { (authResult, error) in
if let error = error {
print("Failed to sign in: \(error.localizedDescription)")
}
})
Copy link
Member

@ncooke3 ncooke3 Apr 15, 2021

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 {
Copy link
Member

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
Copy link
Member

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()
Copy link
Member

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

Copy link
Author

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.

Comment on lines 69 to 70
guard let imagePath = UserDefaults.standard.string(forKey: self.photoStore.imagePathKey) else { return }
self.photoStore.downloadImage(atPath: imagePath)
Copy link
Member

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

Comment on lines 65 to 67
if self.source == .camera {
imagePicker.sourceType = .camera
imagePicker.cameraCaptureMode = .photo
} else {
imagePicker.sourceType = .photoLibrary
}
Copy link
Member

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 {
Copy link
Member

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

Copy link
Member

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

Copy link
Author

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:

  1. PHPickerViewController does not provide any access to the camera yet, so I was forced to also incorporate UIImagePickerController or get a camera manually.

  2. 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.

Copy link
Member

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 {
Copy link
Member

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
}

Comment on lines 38 to 48
Button("❌") {
showUploadMenu = false
}
Copy link
Member

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")
  })

Copy link
Member

Choose a reason for hiding this comment

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

And side note, maybe remove this button entirely and instead have a "Done" button in the top right of the photo picker. I think might be a system button that you can enable (i think this functionality provided somewhere for free.. happy to help). It would then look like:
Screen Shot 2021-04-15 at 4 16 13 PM

Copy link
Author

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 {
Copy link
Member

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 🤞

Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants