diff options
Diffstat (limited to 'Example/tvOSSample/tvOSSample/StorageViewController.swift')
-rw-r--r-- | Example/tvOSSample/tvOSSample/StorageViewController.swift | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/Example/tvOSSample/tvOSSample/StorageViewController.swift b/Example/tvOSSample/tvOSSample/StorageViewController.swift new file mode 100644 index 0000000..4416649 --- /dev/null +++ b/Example/tvOSSample/tvOSSample/StorageViewController.swift @@ -0,0 +1,148 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import UIKit +import FirebaseStorage + +class StorageViewController: UIViewController { + /// An enum describing the different states of the view controller. + private enum UIState: Equatable { + /// No image is being shown, waiting on user action. + case cleared + + /// Currently downloading from Firebase. + case downloading(StorageTask) + + /// The image has downloaded and should be displayed. + case downloaded(UIImage) + + /// Show an error message and stop downloading. + case failed(String) + + /// Equatable support for UIState. + static func ==(lhs: StorageViewController.UIState, rhs: StorageViewController.UIState) -> Bool { + switch (lhs, rhs) { + case (.cleared, .cleared): return true + case (.downloading, .downloading): return true + case (.downloaded, .downloaded): return true + case (.failed, .failed): return true + default: return false + } + } + } + + /// MARK: - Properties + + /// The current internal state of the view controller. + private var state: UIState = .cleared { + didSet { changeState(from: oldValue, to: state) } + } + + // MARK: Interface + + /// Image view to display the downloaded image. + @IBOutlet weak var imageView: UIImageView! + + /// The download button. + @IBOutlet weak var downloadButton: UIButton! + + /// The clear button. + @IBOutlet weak var clearButton: UIButton! + + /// A visual representation of the state. + @IBOutlet weak var stateLabel: UILabel! + + // MARK: - User Actions + + @IBAction func downloadButtonHit(_ sender: UIButton) { + guard case .cleared = state else { return } + + // Start the download. + let storage = Storage.storage() + let ref = storage.reference(withPath: Constants.downloadPath) + // TODO: Show progress bar here using proper API. + let task = ref.getData(maxSize: Constants.maxSize) { [unowned self] (data, error) in + guard let data = data else { + self.state = .failed("Error downloading: \(error!.localizedDescription)") + return + } + + // Create a UIImage from the PNG data. + guard let image = UIImage(data: data) else { + self.state = .failed("Unable to initialize image with data downloaded.") + return + } + + self.state = .downloaded(image) + } + + // The completion block above could be run before this line in some situations. If that's the + // case, we don't need to do anything else and can return. + if case .downloaded = state { return } + + // Set the state to downloading! + state = .downloading(task) + } + + @IBAction func clearButtonHit(_ sender: UIButton) { + guard case .downloaded = state else { return } + + state = .cleared + } + + // MARK: - State Management + + /// Changing from old state to new state. + private func changeState(from oldState: UIState, to newState: UIState) { + if oldState == newState { return } + + switch (oldState, newState) { + // Regular state, start downloading the image. + case (.cleared, .downloading(_)): + // TODO: Update the UI with a spinner? Progress update? + stateLabel.text = "State: Downloading..." + + // Download complete, ensure the download button is still off and enable the clear button. + case (_, .downloaded(let image)): + imageView.image = image + stateLabel.text = "State: Image downloaded!" + + // Clear everything and reset to the original state. + case (_, .cleared): + imageView.image = nil + stateLabel.text = "State: Pending download" + + // An error occurred. + case (_, .failed(let error)): + stateLabel.text = "State: \(error)" + + // For now, as the default, throw a fatal error because it's an unexpected state. This will + // allow us to catch it immediately and add the required action or fix the bug. + default: + fatalError("Programmer error! Tried to go from \(oldState) to \(newState)") + } + } + + // MARK: - Constants + + /// Internal constants for this class. + private struct Constants { + /// The image name to download. Can comment this out and replace it with the other below it as + /// part of the demo. Ensure that Storage has an image uploaded to this path for this to + /// function properly. + static let downloadPath = "YOUR_IMAGE_NAME.jpg" + + static let maxSize: Int64 = 1024 * 1024 * 10 // ~10MB + } +} |