Skip to content

Commit

Permalink
Add a code load status snackbar for iOS frontend (#1530)
Browse files Browse the repository at this point in the history
  • Loading branch information
JakeWharton authored Sep 29, 2023
1 parent 7ff0488 commit 68b5332
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.flow.flowOf
import platform.Foundation.NSLog
import platform.Foundation.NSOperationQueue
import platform.Foundation.NSURLSession

class EmojiSearchLauncher(
Expand All @@ -40,7 +41,7 @@ class EmojiSearchLauncher(
private val manifestUrl = "http://localhost:8080/manifest.zipline.json"

@Suppress("unused") // Invoked in Swift.
fun createTreehouseApp(): TreehouseApp<EmojiSearchPresenter> {
fun createTreehouseApp(listener: EmojiSearchEventListener): TreehouseApp<EmojiSearchPresenter> {
val ziplineHttpClient = nsurlSession.asZiplineHttpClient()

val treehouseAppFactory = TreehouseAppFactory(
Expand All @@ -49,10 +50,16 @@ class EmojiSearchLauncher(
eventListener = object : EventListener() {
override fun codeLoadFailed(app: TreehouseApp<*>, manifestUrl: String?, exception: Exception, startValue: Any?) {
NSLog("Treehouse: codeLoadFailed: $exception")
NSOperationQueue.mainQueue.addOperationWithBlock {
listener.codeLoadFailed()
}
}

override fun codeLoadSuccess(app: TreehouseApp<*>, manifestUrl: String?, manifest: ZiplineManifest, zipline: Zipline, startValue: Any?) {
NSLog("Treehouse: codeLoadSuccess")
NSOperationQueue.mainQueue.addOperationWithBlock {
listener.codeLoadSuccess()
}
}
},
)
Expand All @@ -73,3 +80,8 @@ class EmojiSearchLauncher(
return treehouseApp
}
}

interface EmojiSearchEventListener {
fun codeLoadFailed()
fun codeLoadSuccess()
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objectVersion = 52;
objects = {

/* Begin PBXBuildFile section */
Expand All @@ -16,6 +16,7 @@
AACC042628AC72AC00721342 /* RemoteImageLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = AACC042528AC72AC00721342 /* RemoteImageLoader.swift */; };
C2F7CE6628BEAB6C00A66A69 /* ImageBinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2F7CE6528BEAB6C00A66A69 /* ImageBinding.swift */; };
C2F7FBA228BEB54200A66A69 /* TextInputBinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2F7FBA128BEB54200A66A69 /* TextInputBinding.swift */; };
CB5D6B092AC5326B004BF9CB /* SnackBar in Frameworks */ = {isa = PBXBuildFile; productRef = CB5D6B082AC5326B004BF9CB /* SnackBar */; };
CB85C0B725AFE61A007A2CC7 /* EmojiSearchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB85C0B625AFE61A007A2CC7 /* EmojiSearchViewController.swift */; };
CB9F76562810A8A8008CF457 /* IosHostApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB9F76552810A8A8008CF457 /* IosHostApi.swift */; };
/* End PBXBuildFile section */
Expand All @@ -42,6 +43,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
CB5D6B092AC5326B004BF9CB /* SnackBar in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -101,6 +103,9 @@
dependencies = (
);
name = EmojiSearchApp;
packageProductDependencies = (
CB5D6B082AC5326B004BF9CB /* SnackBar */,
);
productName = EmojiSearchApp;
productReference = 635661D121F12B7E00DD7240 /* EmojiSearchApp.app */;
productType = "com.apple.product-type.application";
Expand Down Expand Up @@ -130,6 +135,9 @@
Base,
);
mainGroup = 635661C821F12B7D00DD7240;
packageReferences = (
CB5D6B072AC5326B004BF9CB /* XCRemoteSwiftPackageReference "SnackBar" */,
);
productRefGroup = 635661D221F12B7E00DD7240 /* Products */;
projectDirPath = "";
projectRoot = "";
Expand Down Expand Up @@ -415,6 +423,25 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */

/* Begin XCRemoteSwiftPackageReference section */
CB5D6B072AC5326B004BF9CB /* XCRemoteSwiftPackageReference "SnackBar" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/ahmedAlmasri/SnackBar.swift";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 0.1.2;
};
};
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
CB5D6B082AC5326B004BF9CB /* SnackBar */ = {
isa = XCSwiftPackageProductDependency;
package = CB5D6B072AC5326B004BF9CB /* XCRemoteSwiftPackageReference "SnackBar" */;
productName = SnackBar;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 635661C921F12B7D00DD7240 /* Project object */;
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@
import Foundation
import UIKit
import EmojiSearchKt
import SnackBar

class EmojiSearchViewController : UIViewController {

class EmojiSearchViewController : UIViewController, EmojiSearchEventListener {
// MARK: - Private Properties

private let urlSession: URLSession = .init(configuration: .default)
private var success = true
private var snackBar: SnackBarPresentable? = nil

// MARK: - UIViewController

Expand All @@ -34,7 +36,7 @@ class EmojiSearchViewController : UIViewController {

override func loadView() {
let emojiSearchLauncher = EmojiSearchLauncher(nsurlSession: urlSession, hostApi: IosHostApi())
let treehouseApp = emojiSearchLauncher.createTreehouseApp()
let treehouseApp = emojiSearchLauncher.createTreehouseApp(listener: self)
let widgetSystem = EmojiSearchWidgetSystem(treehouseApp: treehouseApp)
let treehouseView = TreehouseUIView(widgetSystem: widgetSystem)
let content = treehouseApp.createContent(
Expand All @@ -44,6 +46,29 @@ class EmojiSearchViewController : UIViewController {
ExposedKt.bindWhenReady(content: content, view: treehouseView)
view = treehouseView.view
}

func codeLoadFailed() {
if (success) {
// Only show the Snackbar on the first transition from success.
success = false
let snackBar = SnackBar.make(in: view, message: "Unable to load guest code from server", duration: SnackBar.Duration.infinite)
.setAction(with: "Dismiss", action: { self.maybeDismissSnackBar() })
snackBar.show()
self.snackBar = snackBar
}
}

func codeLoadSuccess() {
success = true
maybeDismissSnackBar()
}

private func maybeDismissSnackBar() {
if let snackBar = snackBar {
snackBar.dismiss()
self.snackBar = nil
}
}
}

class EmojiSearchContent : TreehouseContentSource {
Expand Down

0 comments on commit 68b5332

Please sign in to comment.