From c4be18d081b75bbcab66ede6875ca2b5dccec8c9 Mon Sep 17 00:00:00 2001 From: Alex Skorulis Date: Thu, 1 Dec 2022 15:21:20 +1100 Subject: [PATCH 01/13] Initial SwiftUI setup --- .../redwood/treehouse/TreehouseSwiftUIView.kt | 55 +++ .../cash/redwood/widget/SwiftUIChildren.kt | 48 +++ .../EmojiSearchApp.xcodeproj/project.pbxproj | 407 ++++++++++++++++++ .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 13 + .../Assets.xcassets/Contents.json | 6 + .../swiftUI/EmojiSearchApp/ContentView.swift | 22 + .../EmojiSearchApp/EmojiSearchAppApp.swift | 22 + .../Preview Assets.xcassets/Contents.json | 6 + .../EmojiSearchApp/Service/IosHostApi.swift | 45 ++ samples/emoji-search/ios/swiftUI/Podfile | 6 + samples/emoji-search/ios/swiftUI/Podfile.lock | 16 + 12 files changed, 657 insertions(+) create mode 100644 redwood-treehouse/src/iosMain/kotlin/app/cash/redwood/treehouse/TreehouseSwiftUIView.kt create mode 100644 redwood-widget/src/iosMain/kotlin/app/cash/redwood/widget/SwiftUIChildren.kt create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp.xcodeproj/project.pbxproj create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/Assets.xcassets/Contents.json create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/ContentView.swift create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/EmojiSearchAppApp.swift create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/Preview Content/Preview Assets.xcassets/Contents.json create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/Service/IosHostApi.swift create mode 100644 samples/emoji-search/ios/swiftUI/Podfile create mode 100644 samples/emoji-search/ios/swiftUI/Podfile.lock diff --git a/redwood-treehouse/src/iosMain/kotlin/app/cash/redwood/treehouse/TreehouseSwiftUIView.kt b/redwood-treehouse/src/iosMain/kotlin/app/cash/redwood/treehouse/TreehouseSwiftUIView.kt new file mode 100644 index 0000000000..a11fb8e56d --- /dev/null +++ b/redwood-treehouse/src/iosMain/kotlin/app/cash/redwood/treehouse/TreehouseSwiftUIView.kt @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2022 Square, Inc. + * + * 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. + */ + +package app.cash.redwood.treehouse + +import app.cash.redwood.treehouse.TreehouseView.CodeListener +import app.cash.redwood.widget.SwiftUIChildren +import app.cash.redwood.widget.SwiftUIView +import app.cash.redwood.widget.Widget +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow + +public class TreehouseSwiftUIView( + private val treehouseApp: TreehouseApp, + override val widgetSystem: TreehouseView.WidgetSystem, +) : TreehouseView, SwiftUIView { + + public override var codeListener: CodeListener = CodeListener() + private var content: TreehouseView.Content? = null + + private val _children = SwiftUIChildren(this) + override val children: Widget.Children<*> = _children + + override fun reset() { + _children.remove(0, _children.widgets.size) + } + + override val boundContent: TreehouseView.Content? + get() = content + + private val mutableHostConfiguration = MutableStateFlow(HostConfiguration()) + + override val hostConfiguration: StateFlow + get() = mutableHostConfiguration + + public fun setContent(content: TreehouseView.Content) { + treehouseApp.dispatchers.checkUi() + this.content = content + treehouseApp.onContentChanged(this) + } + +} diff --git a/redwood-widget/src/iosMain/kotlin/app/cash/redwood/widget/SwiftUIChildren.kt b/redwood-widget/src/iosMain/kotlin/app/cash/redwood/widget/SwiftUIChildren.kt new file mode 100644 index 0000000000..c4ff700e88 --- /dev/null +++ b/redwood-widget/src/iosMain/kotlin/app/cash/redwood/widget/SwiftUIChildren.kt @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2022 Square, Inc. + * + * 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. + */ +package app.cash.redwood.widget + +import kotlinx.cinterop.convert +import platform.darwin.NSInteger + +public interface SwiftUIView { + +} + +public class SwiftUIChildren( + private val parent: SwiftUIView, +) : Widget.Children { + + private val _widgets = MutableListChildren() + public val widgets: List> = _widgets + + override fun insert(index: Int, widget: Widget) { + _widgets.add(index, widget) + } + + override fun move(fromIndex: Int, toIndex: Int, count: Int) { + _widgets.move(fromIndex, toIndex, count) + } + + override fun remove(index: Int, count: Int) { + _widgets.remove(index, count) + } + + override fun onLayoutModifierUpdated(index: Int) { + // TODO + } + +} diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp.xcodeproj/project.pbxproj b/samples/emoji-search/ios/swiftUI/EmojiSearchApp.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..de0eaa3242 --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp.xcodeproj/project.pbxproj @@ -0,0 +1,407 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + 320A9E3134B16AB401CAB3B3 /* Pods_EmojiSearchApp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2B340877E75215F2AED9BA8 /* Pods_EmojiSearchApp.framework */; }; + C4A751332938580300D3F831 /* EmojiSearchAppApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A751322938580300D3F831 /* EmojiSearchAppApp.swift */; }; + C4A751352938580300D3F831 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A751342938580300D3F831 /* ContentView.swift */; }; + C4A751372938580400D3F831 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C4A751362938580400D3F831 /* Assets.xcassets */; }; + C4A7513A2938580400D3F831 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C4A751392938580400D3F831 /* Preview Assets.xcassets */; }; + C4A7515E2938598D00D3F831 /* IosHostApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A7515D2938598D00D3F831 /* IosHostApi.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 8D728DFB15C556F9D94C2A56 /* Pods-EmojiSearchApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-EmojiSearchApp.release.xcconfig"; path = "Target Support Files/Pods-EmojiSearchApp/Pods-EmojiSearchApp.release.xcconfig"; sourceTree = ""; }; + B1676165A1782330A65CC380 /* Pods-EmojiSearchApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-EmojiSearchApp.debug.xcconfig"; path = "Target Support Files/Pods-EmojiSearchApp/Pods-EmojiSearchApp.debug.xcconfig"; sourceTree = ""; }; + C4A7512F2938580300D3F831 /* EmojiSearchApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = EmojiSearchApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; + C4A751322938580300D3F831 /* EmojiSearchAppApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiSearchAppApp.swift; sourceTree = ""; }; + C4A751342938580300D3F831 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + C4A751362938580400D3F831 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + C4A751392938580400D3F831 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + C4A7515D2938598D00D3F831 /* IosHostApi.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IosHostApi.swift; sourceTree = ""; }; + D2B340877E75215F2AED9BA8 /* Pods_EmojiSearchApp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_EmojiSearchApp.framework; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + C4A7512C2938580300D3F831 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 320A9E3134B16AB401CAB3B3 /* Pods_EmojiSearchApp.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 357551702BEA7BF2ED0FCB07 /* Pods */ = { + isa = PBXGroup; + children = ( + B1676165A1782330A65CC380 /* Pods-EmojiSearchApp.debug.xcconfig */, + 8D728DFB15C556F9D94C2A56 /* Pods-EmojiSearchApp.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; + C4A751262938580300D3F831 = { + isa = PBXGroup; + children = ( + C4A751312938580300D3F831 /* EmojiSearchApp */, + C4A751302938580300D3F831 /* Products */, + 357551702BEA7BF2ED0FCB07 /* Pods */, + C5145E45B03AF805A56E7F75 /* Frameworks */, + ); + sourceTree = ""; + }; + C4A751302938580300D3F831 /* Products */ = { + isa = PBXGroup; + children = ( + C4A7512F2938580300D3F831 /* EmojiSearchApp.app */, + ); + name = Products; + sourceTree = ""; + }; + C4A751312938580300D3F831 /* EmojiSearchApp */ = { + isa = PBXGroup; + children = ( + C4A7515C2938598600D3F831 /* Service */, + C4A751322938580300D3F831 /* EmojiSearchAppApp.swift */, + C4A751342938580300D3F831 /* ContentView.swift */, + C4A751362938580400D3F831 /* Assets.xcassets */, + C4A751382938580400D3F831 /* Preview Content */, + ); + path = EmojiSearchApp; + sourceTree = ""; + }; + C4A751382938580400D3F831 /* Preview Content */ = { + isa = PBXGroup; + children = ( + C4A751392938580400D3F831 /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; + C4A7515C2938598600D3F831 /* Service */ = { + isa = PBXGroup; + children = ( + C4A7515D2938598D00D3F831 /* IosHostApi.swift */, + ); + path = Service; + sourceTree = ""; + }; + C5145E45B03AF805A56E7F75 /* Frameworks */ = { + isa = PBXGroup; + children = ( + D2B340877E75215F2AED9BA8 /* Pods_EmojiSearchApp.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + C4A7512E2938580300D3F831 /* EmojiSearchApp */ = { + isa = PBXNativeTarget; + buildConfigurationList = C4A751532938580400D3F831 /* Build configuration list for PBXNativeTarget "EmojiSearchApp" */; + buildPhases = ( + A61F947B27146E75CBC8EECC /* [CP] Check Pods Manifest.lock */, + C4A7512B2938580300D3F831 /* Sources */, + C4A7512C2938580300D3F831 /* Frameworks */, + C4A7512D2938580300D3F831 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = EmojiSearchApp; + productName = EmojiSearchApp; + productReference = C4A7512F2938580300D3F831 /* EmojiSearchApp.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + C4A751272938580300D3F831 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1410; + LastUpgradeCheck = 1410; + TargetAttributes = { + C4A7512E2938580300D3F831 = { + CreatedOnToolsVersion = 14.1; + }; + }; + }; + buildConfigurationList = C4A7512A2938580300D3F831 /* Build configuration list for PBXProject "EmojiSearchApp" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = C4A751262938580300D3F831; + productRefGroup = C4A751302938580300D3F831 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + C4A7512E2938580300D3F831 /* EmojiSearchApp */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + C4A7512D2938580300D3F831 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C4A7513A2938580400D3F831 /* Preview Assets.xcassets in Resources */, + C4A751372938580400D3F831 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + A61F947B27146E75CBC8EECC /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-EmojiSearchApp-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + C4A7512B2938580300D3F831 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C4A751352938580300D3F831 /* ContentView.swift in Sources */, + C4A7515E2938598D00D3F831 /* IosHostApi.swift in Sources */, + C4A751332938580300D3F831 /* EmojiSearchAppApp.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + C4A751512938580400D3F831 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.1; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + C4A751522938580400D3F831 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.1; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + C4A751542938580400D3F831 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B1676165A1782330A65CC380 /* Pods-EmojiSearchApp.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"EmojiSearchApp/Preview Content\""; + DEVELOPMENT_TEAM = ZJF5329K3Z; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.squareup.cash.EmojiSearchApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + C4A751552938580400D3F831 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8D728DFB15C556F9D94C2A56 /* Pods-EmojiSearchApp.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"EmojiSearchApp/Preview Content\""; + DEVELOPMENT_TEAM = ZJF5329K3Z; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.squareup.cash.EmojiSearchApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + C4A7512A2938580300D3F831 /* Build configuration list for PBXProject "EmojiSearchApp" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C4A751512938580400D3F831 /* Debug */, + C4A751522938580400D3F831 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C4A751532938580400D3F831 /* Build configuration list for PBXNativeTarget "EmojiSearchApp" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C4A751542938580400D3F831 /* Debug */, + C4A751552938580400D3F831 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = C4A751272938580300D3F831 /* Project object */; +} diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Assets.xcassets/AccentColor.colorset/Contents.json b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000000..eb87897008 --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Assets.xcassets/AppIcon.appiconset/Contents.json b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..13613e3ee1 --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Assets.xcassets/Contents.json b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Assets.xcassets/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/ContentView.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/ContentView.swift new file mode 100644 index 0000000000..26db2fea2c --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/ContentView.swift @@ -0,0 +1,22 @@ +// Created by Alexander skorulis on 1/12/2022. +// Copyright © Square, Inc. All rights reserved. + +import SwiftUI + +struct ContentView: View { + var body: some View { + VStack { + Image(systemName: "globe") + .imageScale(.large) + .foregroundColor(.accentColor) + Text("Hello, world!") + } + .padding() + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/EmojiSearchAppApp.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/EmojiSearchAppApp.swift new file mode 100644 index 0000000000..193bb58167 --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/EmojiSearchAppApp.swift @@ -0,0 +1,22 @@ +// Created by Alexander skorulis on 1/12/2022. +// Copyright © Square, Inc. All rights reserved. + +import SwiftUI +import shared + +@main +struct EmojiSearchAppApp: App { + + private let urlSession: URLSession = .init(configuration: .default) + + init() { + let emojiSearchLauncher = EmojiSearchLauncher(nsurlSession: urlSession, hostApi: IosHostApi()) + let treehouseApp = emojiSearchLauncher.createTreehouseApp() + } + + var body: some Scene { + WindowGroup { + ContentView() + } + } +} diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Preview Content/Preview Assets.xcassets/Contents.json b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Service/IosHostApi.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Service/IosHostApi.swift new file mode 100644 index 0000000000..b71585b569 --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Service/IosHostApi.swift @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2022 Square, Inc. + * + * 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 Foundation +import shared + +class IosHostApi : PresentersHostApi { + private let client: URLSession = .init(configuration: .default) + + func httpCall(url: String, headers: [String : String], completionHandler: @escaping (String?, Error?) -> Void) { + var request = URLRequest(url: URL(string: url)!) + for (name, value) in headers { + request.addValue(value, forHTTPHeaderField: name) + } + let task = client.dataTask(with: request) { data, response, error in + // The KMM memory model doesn't do shared objects well, so Zipline expects the callback + // on the same thread that the download was initiated from. This happens to be the main + // thread, so we can bounce back to that thread for now. + // Switching to the new KMM memory model may remove the need for this. + DispatchQueue.main.async { + completionHandler(data.map { + return String(decoding: $0, as: UTF8.self) + }, error) + } + } + + task.resume() + } + + func close() { + } +} diff --git a/samples/emoji-search/ios/swiftUI/Podfile b/samples/emoji-search/ios/swiftUI/Podfile new file mode 100644 index 0000000000..af350fdab0 --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/Podfile @@ -0,0 +1,6 @@ +platform :ios, '14.0' +use_frameworks! + +target 'EmojiSearchApp' do + pod 'shared', :path => '../shared' +end diff --git a/samples/emoji-search/ios/swiftUI/Podfile.lock b/samples/emoji-search/ios/swiftUI/Podfile.lock new file mode 100644 index 0000000000..2c12e94531 --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/Podfile.lock @@ -0,0 +1,16 @@ +PODS: + - shared (1.0) + +DEPENDENCIES: + - shared (from `../shared`) + +EXTERNAL SOURCES: + shared: + :path: "../shared" + +SPEC CHECKSUMS: + shared: 2a1e25c6c0e9935e0bebc8574ba39d28f28e9e6f + +PODFILE CHECKSUM: 419b78dd95f0fd0f1760f0ae6490212bce9db60c + +COCOAPODS: 1.11.3 From d822f5f405cf6a0e6212e92fa59acbfdca580150 Mon Sep 17 00:00:00 2001 From: Alex Skorulis Date: Tue, 6 Dec 2022 09:44:59 +1100 Subject: [PATCH 02/13] Get SwiftUI emoji search working --- .../redwood/treehouse/TreehouseSwiftUIView.kt | 3 +- .../cash/redwood/widget/SwiftUIChildren.kt | 4 + .../zipline/samples/emojisearch/exposed.kt | 12 ++ .../EmojiSearchApp.xcodeproj/project.pbxproj | 156 +++++++++++++++--- .../xcschemes/EmojiSearchApp.xcscheme | 78 +++++++++ .../swiftUI/EmojiSearchApp/ContentView.swift | 22 --- .../EmojiSearchApp/Core/EnvironmentKeys.swift | 32 ++++ .../EmojiSearchApp/Core/SwiftUIView.swift | 12 ++ .../Core/TreehouseUIRenderer.swift | 40 +++++ .../Core/TreehouseViewRenderer.swift | 16 ++ .../Core/WidgetChildrenObserver.swift | 19 +++ .../Core/WidgetChildrenView.swift | 35 ++++ .../EmojiSearchApp/EmojiSearchAppApp.swift | 22 --- .../AccentColor.colorset/Contents.json | 0 .../AppIcon.appiconset/Contents.json | 0 .../Assets.xcassets/Contents.json | 0 .../Preview Assets.xcassets/Contents.json | 0 .../EmojiSearchApp/Scene/ContentView.swift | 21 +++ .../Scene/ContentViewModel.swift | 27 +++ .../EmojiSearchApp/Scene/EmojiSearchApp.swift | 41 +++++ .../Service/RemoteImageLoader.swift | 40 +++++ .../EmojiSearchApp/Widget/ColumnBinding.swift | 59 +++++++ .../EmojiSearchApp/Widget/ImageBinding.swift | 38 +++++ .../Widget/LazyColumnBinding.swift | 52 ++++++ .../EmojiSearchApp/Widget/RowBinding.swift | 54 ++++++ .../EmojiSearchApp/Widget/TextBinding.swift | 28 ++++ .../Widget/TextInputBinding.swift | 65 ++++++++ .../SwiftUIEmojiSearchWidgetFactory.swift | 24 +++ .../SwiftUILayoutWidgetFactory.swift | 11 ++ .../SwiftUILazyLayoutWidgetFactory.swift | 11 ++ 30 files changed, 853 insertions(+), 69 deletions(-) create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp.xcodeproj/xcshareddata/xcschemes/EmojiSearchApp.xcscheme delete mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/ContentView.swift create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/EnvironmentKeys.swift create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/SwiftUIView.swift create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/TreehouseUIRenderer.swift create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/TreehouseViewRenderer.swift create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenObserver.swift create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenView.swift delete mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/EmojiSearchAppApp.swift rename samples/emoji-search/ios/swiftUI/EmojiSearchApp/{ => Resource}/Assets.xcassets/AccentColor.colorset/Contents.json (100%) rename samples/emoji-search/ios/swiftUI/EmojiSearchApp/{ => Resource}/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename samples/emoji-search/ios/swiftUI/EmojiSearchApp/{ => Resource}/Assets.xcassets/Contents.json (100%) rename samples/emoji-search/ios/swiftUI/EmojiSearchApp/{ => Resource}/Preview Content/Preview Assets.xcassets/Contents.json (100%) create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/ContentView.swift create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/ContentViewModel.swift create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/EmojiSearchApp.swift create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/Service/RemoteImageLoader.swift create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ImageBinding.swift create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/LazyColumnBinding.swift create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/RowBinding.swift create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextBinding.swift create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextInputBinding.swift create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUIEmojiSearchWidgetFactory.swift create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUILayoutWidgetFactory.swift create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUILazyLayoutWidgetFactory.swift diff --git a/redwood-treehouse/src/iosMain/kotlin/app/cash/redwood/treehouse/TreehouseSwiftUIView.kt b/redwood-treehouse/src/iosMain/kotlin/app/cash/redwood/treehouse/TreehouseSwiftUIView.kt index a11fb8e56d..97d80848fb 100644 --- a/redwood-treehouse/src/iosMain/kotlin/app/cash/redwood/treehouse/TreehouseSwiftUIView.kt +++ b/redwood-treehouse/src/iosMain/kotlin/app/cash/redwood/treehouse/TreehouseSwiftUIView.kt @@ -33,6 +33,7 @@ public class TreehouseSwiftUIView( private val _children = SwiftUIChildren(this) override val children: Widget.Children<*> = _children + public override var stateChangeListener: TreehouseView.OnStateChangeListener? = null override fun reset() { _children.remove(0, _children.widgets.size) @@ -49,7 +50,7 @@ public class TreehouseSwiftUIView( public fun setContent(content: TreehouseView.Content) { treehouseApp.dispatchers.checkUi() this.content = content - treehouseApp.onContentChanged(this) + stateChangeListener?.onStateChanged(this) } } diff --git a/redwood-widget/src/iosMain/kotlin/app/cash/redwood/widget/SwiftUIChildren.kt b/redwood-widget/src/iosMain/kotlin/app/cash/redwood/widget/SwiftUIChildren.kt index c4ff700e88..a9c429068b 100644 --- a/redwood-widget/src/iosMain/kotlin/app/cash/redwood/widget/SwiftUIChildren.kt +++ b/redwood-widget/src/iosMain/kotlin/app/cash/redwood/widget/SwiftUIChildren.kt @@ -28,17 +28,21 @@ public class SwiftUIChildren( private val _widgets = MutableListChildren() public val widgets: List> = _widgets + public var observer: (() -> Unit)? = null override fun insert(index: Int, widget: Widget) { _widgets.add(index, widget) + observer?.invoke() } override fun move(fromIndex: Int, toIndex: Int, count: Int) { _widgets.move(fromIndex, toIndex, count) + observer?.invoke() } override fun remove(index: Int, count: Int) { _widgets.remove(index, count) + observer?.invoke() } override fun onLayoutModifierUpdated(index: Int) { diff --git a/samples/emoji-search/ios/shared/src/commonMain/kotlin/app/cash/zipline/samples/emojisearch/exposed.kt b/samples/emoji-search/ios/shared/src/commonMain/kotlin/app/cash/zipline/samples/emojisearch/exposed.kt index 84e5973029..30d793e404 100644 --- a/samples/emoji-search/ios/shared/src/commonMain/kotlin/app/cash/zipline/samples/emojisearch/exposed.kt +++ b/samples/emoji-search/ios/shared/src/commonMain/kotlin/app/cash/zipline/samples/emojisearch/exposed.kt @@ -21,12 +21,18 @@ import app.cash.redwood.LayoutModifier import app.cash.redwood.layout.uiview.UIViewRedwoodLayoutWidgetFactory import app.cash.redwood.treehouse.TreehouseUIKitView import app.cash.redwood.treehouse.TreehouseView +import app.cash.redwood.treehouse.TreehouseSwiftUIView +import app.cash.redwood.widget.SwiftUIView +import app.cash.redwood.widget.SwiftUIChildren import app.cash.redwood.treehouse.lazylayout.uiview.UIViewRedwoodTreehouseLazyLayoutWidgetFactory import example.schema.widget.EmojiSearchDiffConsumingNodeFactory import example.schema.widget.EmojiSearchWidgetFactory import okio.ByteString import okio.toByteString import platform.Foundation.NSData +import app.cash.redwood.layout.widget.RedwoodLayoutWidgetFactory +import kotlinx.coroutines.flow.StateFlow +import app.cash.redwood.treehouse.HostConfiguration // Used to export types to Objective-C / Swift. fun exposedTypes( @@ -38,6 +44,12 @@ fun exposedTypes( uiViewRedwoodTreehouseLazyLayoutWidgetFactory: UIViewRedwoodTreehouseLazyLayoutWidgetFactory<*>, widgetSystem: TreehouseView.WidgetSystem<*>, diffConsumingNodeFactory: EmojiSearchDiffConsumingNodeFactory<*>, + treehouseSwiftUIView: TreehouseSwiftUIView<*>, + layoutWidgetFactory: RedwoodLayoutWidgetFactory<*>, + swiftUIView: SwiftUIView, + swiftUIChildren: SwiftUIChildren, + stateFlow: StateFlow<*>, + hostConfiguration: HostConfiguration ) { throw AssertionError() } diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp.xcodeproj/project.pbxproj b/samples/emoji-search/ios/swiftUI/EmojiSearchApp.xcodeproj/project.pbxproj index de0eaa3242..dd861dc4e3 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp.xcodeproj/project.pbxproj +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp.xcodeproj/project.pbxproj @@ -3,28 +3,62 @@ archiveVersion = 1; classes = { }; - objectVersion = 56; + objectVersion = 50; objects = { /* Begin PBXBuildFile section */ 320A9E3134B16AB401CAB3B3 /* Pods_EmojiSearchApp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2B340877E75215F2AED9BA8 /* Pods_EmojiSearchApp.framework */; }; - C4A751332938580300D3F831 /* EmojiSearchAppApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A751322938580300D3F831 /* EmojiSearchAppApp.swift */; }; - C4A751352938580300D3F831 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A751342938580300D3F831 /* ContentView.swift */; }; - C4A751372938580400D3F831 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C4A751362938580400D3F831 /* Assets.xcassets */; }; - C4A7513A2938580400D3F831 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C4A751392938580400D3F831 /* Preview Assets.xcassets */; }; C4A7515E2938598D00D3F831 /* IosHostApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A7515D2938598D00D3F831 /* IosHostApi.swift */; }; + C4A751672938674300D3F831 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C4A751642938674300D3F831 /* Assets.xcassets */; }; + C4A751682938674300D3F831 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C4A751662938674300D3F831 /* Preview Assets.xcassets */; }; + C4A7516B29386A9F00D3F831 /* TextInputBinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A7516A29386A9F00D3F831 /* TextInputBinding.swift */; }; + C4A7516E2938734100D3F831 /* SwiftUIEmojiSearchWidgetFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A7516D2938734100D3F831 /* SwiftUIEmojiSearchWidgetFactory.swift */; }; + C4A751702938734700D3F831 /* SwiftUILayoutWidgetFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A7516F2938734700D3F831 /* SwiftUILayoutWidgetFactory.swift */; }; + C4A75172293873E700D3F831 /* ColumnBinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A75171293873E700D3F831 /* ColumnBinding.swift */; }; + FA42CB27293C34DE00031CF0 /* SwiftUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA42CB26293C34DE00031CF0 /* SwiftUIView.swift */; }; + FA42CB29293C350200031CF0 /* WidgetChildrenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA42CB28293C350200031CF0 /* WidgetChildrenView.swift */; }; + FA42CB2B293C361100031CF0 /* WidgetChildrenObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA42CB2A293C361100031CF0 /* WidgetChildrenObserver.swift */; }; + FA42CB2D293C3A4C00031CF0 /* LazyColumnBinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA42CB2C293C3A4C00031CF0 /* LazyColumnBinding.swift */; }; + FA42CB2F293C3C3E00031CF0 /* SwiftUILazyLayoutWidgetFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA42CB2E293C3C3E00031CF0 /* SwiftUILazyLayoutWidgetFactory.swift */; }; + FA42CB31293C413500031CF0 /* EnvironmentKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA42CB30293C413500031CF0 /* EnvironmentKeys.swift */; }; + FA42CB33293C466300031CF0 /* TreehouseViewRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA42CB32293C466300031CF0 /* TreehouseViewRenderer.swift */; }; + FA42CB35293C46FC00031CF0 /* RemoteImageLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA42CB34293C46FC00031CF0 /* RemoteImageLoader.swift */; }; + FA42CB3A293C471100031CF0 /* EmojiSearchApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA42CB37293C471100031CF0 /* EmojiSearchApp.swift */; }; + FA42CB3B293C471100031CF0 /* ContentViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA42CB38293C471100031CF0 /* ContentViewModel.swift */; }; + FA42CB3C293C471100031CF0 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA42CB39293C471100031CF0 /* ContentView.swift */; }; + FA42CB3E293C529B00031CF0 /* RowBinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA42CB3D293C529B00031CF0 /* RowBinding.swift */; }; + FA42CB40293C540800031CF0 /* ImageBinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA42CB3F293C540800031CF0 /* ImageBinding.swift */; }; + FA42CB42293C556900031CF0 /* TextBinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA42CB41293C556900031CF0 /* TextBinding.swift */; }; + FA42CB44293C612300031CF0 /* TreehouseUIRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA42CB43293C612300031CF0 /* TreehouseUIRenderer.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 8D728DFB15C556F9D94C2A56 /* Pods-EmojiSearchApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-EmojiSearchApp.release.xcconfig"; path = "Target Support Files/Pods-EmojiSearchApp/Pods-EmojiSearchApp.release.xcconfig"; sourceTree = ""; }; B1676165A1782330A65CC380 /* Pods-EmojiSearchApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-EmojiSearchApp.debug.xcconfig"; path = "Target Support Files/Pods-EmojiSearchApp/Pods-EmojiSearchApp.debug.xcconfig"; sourceTree = ""; }; C4A7512F2938580300D3F831 /* EmojiSearchApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = EmojiSearchApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; - C4A751322938580300D3F831 /* EmojiSearchAppApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiSearchAppApp.swift; sourceTree = ""; }; - C4A751342938580300D3F831 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; - C4A751362938580400D3F831 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - C4A751392938580400D3F831 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; C4A7515D2938598D00D3F831 /* IosHostApi.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IosHostApi.swift; sourceTree = ""; }; + C4A751642938674300D3F831 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + C4A751662938674300D3F831 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + C4A7516A29386A9F00D3F831 /* TextInputBinding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextInputBinding.swift; sourceTree = ""; }; + C4A7516D2938734100D3F831 /* SwiftUIEmojiSearchWidgetFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftUIEmojiSearchWidgetFactory.swift; sourceTree = ""; }; + C4A7516F2938734700D3F831 /* SwiftUILayoutWidgetFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUILayoutWidgetFactory.swift; sourceTree = ""; }; + C4A75171293873E700D3F831 /* ColumnBinding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColumnBinding.swift; sourceTree = ""; }; D2B340877E75215F2AED9BA8 /* Pods_EmojiSearchApp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_EmojiSearchApp.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + FA42CB26293C34DE00031CF0 /* SwiftUIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftUIView.swift; sourceTree = ""; }; + FA42CB28293C350200031CF0 /* WidgetChildrenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetChildrenView.swift; sourceTree = ""; }; + FA42CB2A293C361100031CF0 /* WidgetChildrenObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetChildrenObserver.swift; sourceTree = ""; }; + FA42CB2C293C3A4C00031CF0 /* LazyColumnBinding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LazyColumnBinding.swift; sourceTree = ""; }; + FA42CB2E293C3C3E00031CF0 /* SwiftUILazyLayoutWidgetFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUILazyLayoutWidgetFactory.swift; sourceTree = ""; }; + FA42CB30293C413500031CF0 /* EnvironmentKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnvironmentKeys.swift; sourceTree = ""; }; + FA42CB32293C466300031CF0 /* TreehouseViewRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreehouseViewRenderer.swift; sourceTree = ""; }; + FA42CB34293C46FC00031CF0 /* RemoteImageLoader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteImageLoader.swift; sourceTree = ""; }; + FA42CB37293C471100031CF0 /* EmojiSearchApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmojiSearchApp.swift; sourceTree = ""; }; + FA42CB38293C471100031CF0 /* ContentViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentViewModel.swift; sourceTree = ""; }; + FA42CB39293C471100031CF0 /* ContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + FA42CB3D293C529B00031CF0 /* RowBinding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RowBinding.swift; sourceTree = ""; }; + FA42CB3F293C540800031CF0 /* ImageBinding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageBinding.swift; sourceTree = ""; }; + FA42CB41293C556900031CF0 /* TextBinding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBinding.swift; sourceTree = ""; }; + FA42CB43293C612300031CF0 /* TreehouseUIRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreehouseUIRenderer.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -69,29 +103,63 @@ C4A751312938580300D3F831 /* EmojiSearchApp */ = { isa = PBXGroup; children = ( + FA42CB25293C34CF00031CF0 /* Core */, + C4A751632938674300D3F831 /* Resource */, + FA42CB36293C471100031CF0 /* Scene */, C4A7515C2938598600D3F831 /* Service */, - C4A751322938580300D3F831 /* EmojiSearchAppApp.swift */, - C4A751342938580300D3F831 /* ContentView.swift */, - C4A751362938580400D3F831 /* Assets.xcassets */, - C4A751382938580400D3F831 /* Preview Content */, + C4A7516929386A8100D3F831 /* Widget */, + C4A7516C2938734100D3F831 /* WidgetFactory */, ); path = EmojiSearchApp; sourceTree = ""; }; - C4A751382938580400D3F831 /* Preview Content */ = { + C4A7515C2938598600D3F831 /* Service */ = { + isa = PBXGroup; + children = ( + FA42CB34293C46FC00031CF0 /* RemoteImageLoader.swift */, + C4A7515D2938598D00D3F831 /* IosHostApi.swift */, + ); + path = Service; + sourceTree = ""; + }; + C4A751632938674300D3F831 /* Resource */ = { isa = PBXGroup; children = ( - C4A751392938580400D3F831 /* Preview Assets.xcassets */, + C4A751642938674300D3F831 /* Assets.xcassets */, + C4A751652938674300D3F831 /* Preview Content */, + ); + path = Resource; + sourceTree = ""; + }; + C4A751652938674300D3F831 /* Preview Content */ = { + isa = PBXGroup; + children = ( + C4A751662938674300D3F831 /* Preview Assets.xcassets */, ); path = "Preview Content"; sourceTree = ""; }; - C4A7515C2938598600D3F831 /* Service */ = { + C4A7516929386A8100D3F831 /* Widget */ = { isa = PBXGroup; children = ( - C4A7515D2938598D00D3F831 /* IosHostApi.swift */, + C4A7516A29386A9F00D3F831 /* TextInputBinding.swift */, + C4A75171293873E700D3F831 /* ColumnBinding.swift */, + FA42CB2C293C3A4C00031CF0 /* LazyColumnBinding.swift */, + FA42CB3D293C529B00031CF0 /* RowBinding.swift */, + FA42CB3F293C540800031CF0 /* ImageBinding.swift */, + FA42CB41293C556900031CF0 /* TextBinding.swift */, ); - path = Service; + path = Widget; + sourceTree = ""; + }; + C4A7516C2938734100D3F831 /* WidgetFactory */ = { + isa = PBXGroup; + children = ( + C4A7516D2938734100D3F831 /* SwiftUIEmojiSearchWidgetFactory.swift */, + C4A7516F2938734700D3F831 /* SwiftUILayoutWidgetFactory.swift */, + FA42CB2E293C3C3E00031CF0 /* SwiftUILazyLayoutWidgetFactory.swift */, + ); + path = WidgetFactory; sourceTree = ""; }; C5145E45B03AF805A56E7F75 /* Frameworks */ = { @@ -102,6 +170,29 @@ name = Frameworks; sourceTree = ""; }; + FA42CB25293C34CF00031CF0 /* Core */ = { + isa = PBXGroup; + children = ( + FA42CB26293C34DE00031CF0 /* SwiftUIView.swift */, + FA42CB28293C350200031CF0 /* WidgetChildrenView.swift */, + FA42CB2A293C361100031CF0 /* WidgetChildrenObserver.swift */, + FA42CB30293C413500031CF0 /* EnvironmentKeys.swift */, + FA42CB32293C466300031CF0 /* TreehouseViewRenderer.swift */, + FA42CB43293C612300031CF0 /* TreehouseUIRenderer.swift */, + ); + path = Core; + sourceTree = ""; + }; + FA42CB36293C471100031CF0 /* Scene */ = { + isa = PBXGroup; + children = ( + FA42CB37293C471100031CF0 /* EmojiSearchApp.swift */, + FA42CB38293C471100031CF0 /* ContentViewModel.swift */, + FA42CB39293C471100031CF0 /* ContentView.swift */, + ); + path = Scene; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -160,8 +251,8 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - C4A7513A2938580400D3F831 /* Preview Assets.xcassets in Resources */, - C4A751372938580400D3F831 /* Assets.xcassets in Resources */, + C4A751682938674300D3F831 /* Preview Assets.xcassets in Resources */, + C4A751672938674300D3F831 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -197,9 +288,26 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - C4A751352938580300D3F831 /* ContentView.swift in Sources */, + FA42CB42293C556900031CF0 /* TextBinding.swift in Sources */, + FA42CB31293C413500031CF0 /* EnvironmentKeys.swift in Sources */, + C4A751702938734700D3F831 /* SwiftUILayoutWidgetFactory.swift in Sources */, + FA42CB3C293C471100031CF0 /* ContentView.swift in Sources */, + FA42CB40293C540800031CF0 /* ImageBinding.swift in Sources */, + FA42CB35293C46FC00031CF0 /* RemoteImageLoader.swift in Sources */, + FA42CB27293C34DE00031CF0 /* SwiftUIView.swift in Sources */, + FA42CB3A293C471100031CF0 /* EmojiSearchApp.swift in Sources */, + C4A7516E2938734100D3F831 /* SwiftUIEmojiSearchWidgetFactory.swift in Sources */, C4A7515E2938598D00D3F831 /* IosHostApi.swift in Sources */, - C4A751332938580300D3F831 /* EmojiSearchAppApp.swift in Sources */, + FA42CB2B293C361100031CF0 /* WidgetChildrenObserver.swift in Sources */, + FA42CB29293C350200031CF0 /* WidgetChildrenView.swift in Sources */, + FA42CB2F293C3C3E00031CF0 /* SwiftUILazyLayoutWidgetFactory.swift in Sources */, + FA42CB44293C612300031CF0 /* TreehouseUIRenderer.swift in Sources */, + FA42CB3E293C529B00031CF0 /* RowBinding.swift in Sources */, + FA42CB33293C466300031CF0 /* TreehouseViewRenderer.swift in Sources */, + FA42CB2D293C3A4C00031CF0 /* LazyColumnBinding.swift in Sources */, + C4A7516B29386A9F00D3F831 /* TextInputBinding.swift in Sources */, + C4A75172293873E700D3F831 /* ColumnBinding.swift in Sources */, + FA42CB3B293C471100031CF0 /* ContentViewModel.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -328,7 +436,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_ASSET_PATHS = "\"EmojiSearchApp/Preview Content\""; + DEVELOPMENT_ASSET_PATHS = "\"EmojiSearchApp/Resource/Preview Content\""; DEVELOPMENT_TEAM = ZJF5329K3Z; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; @@ -358,7 +466,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_ASSET_PATHS = "\"EmojiSearchApp/Preview Content\""; + DEVELOPMENT_ASSET_PATHS = "\"EmojiSearchApp/Resource/Preview Content\""; DEVELOPMENT_TEAM = ZJF5329K3Z; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp.xcodeproj/xcshareddata/xcschemes/EmojiSearchApp.xcscheme b/samples/emoji-search/ios/swiftUI/EmojiSearchApp.xcodeproj/xcshareddata/xcschemes/EmojiSearchApp.xcscheme new file mode 100644 index 0000000000..57a8eb9e70 --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp.xcodeproj/xcshareddata/xcschemes/EmojiSearchApp.xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/ContentView.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/ContentView.swift deleted file mode 100644 index 26db2fea2c..0000000000 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/ContentView.swift +++ /dev/null @@ -1,22 +0,0 @@ -// Created by Alexander skorulis on 1/12/2022. -// Copyright © Square, Inc. All rights reserved. - -import SwiftUI - -struct ContentView: View { - var body: some View { - VStack { - Image(systemName: "globe") - .imageScale(.large) - .foregroundColor(.accentColor) - Text("Hello, world!") - } - .padding() - } -} - -struct ContentView_Previews: PreviewProvider { - static var previews: some View { - ContentView() - } -} diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/EnvironmentKeys.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/EnvironmentKeys.swift new file mode 100644 index 0000000000..cce78fd7f9 --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/EnvironmentKeys.swift @@ -0,0 +1,32 @@ +// Copyright © Square, Inc. All rights reserved. + +import Foundation +import shared +import SwiftUI + +public struct TreehouseAppKey: EnvironmentKey { + // TODO: This type shouldn't be bound to PresentersEmojiSearchPresenter + public static var defaultValue: (Redwood_treehouseTreehouseApp)? = nil +} + +public extension EnvironmentValues { + + var treehouseApp: (Redwood_treehouseTreehouseApp)? { + get { self[TreehouseAppKey.self] } + set { self[TreehouseAppKey.self] = newValue } + } +} + +struct WidgetSystemKey: EnvironmentKey { + + static var defaultValue: (EmojiSearchWidgetSystem)? = nil +} + +extension EnvironmentValues { + + var treehouseWidgetSystem: (EmojiSearchWidgetSystem)? { + get { self[WidgetSystemKey.self] } + set { self[WidgetSystemKey.self] = newValue } + } +} + diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/SwiftUIView.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/SwiftUIView.swift new file mode 100644 index 0000000000..d794578b8c --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/SwiftUIView.swift @@ -0,0 +1,12 @@ +// Copyright © Square, Inc. All rights reserved. + +import Foundation +import shared +import SwiftUI + +protocol SwiftUIView: Redwood_widgetSwiftUIView, ObservableObject { + + associatedtype ViewType: View + @ViewBuilder var view: ViewType { get } + +} diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/TreehouseUIRenderer.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/TreehouseUIRenderer.swift new file mode 100644 index 0000000000..59de3e7b11 --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/TreehouseUIRenderer.swift @@ -0,0 +1,40 @@ +// Copyright © Square, Inc. All rights reserved. + +import Foundation +import shared +import SwiftUI + +struct TreehouseUIRenderer: View { + + let treehouseUI: any Redwood_treehouseZiplineTreehouseUi + + @Environment(\.treehouseApp) private var treehouseApp + @Environment(\.treehouseWidgetSystem) private var treehouseWidgetSystem + + var body: some View { + guard let app = treehouseApp, let widgetSystem = treehouseWidgetSystem else { + fatalError("Missing expected environment variables") + } + let view = Redwood_treehouseTreehouseSwiftUIView(treehouseApp: app, widgetSystem: widgetSystem) + app.renderTo(view: view) + let content = ContentWrapper(treehouseUI: treehouseUI) + view.setContent(content: content) + return TreehouseViewRenderer(treehouseView: view) + } + +} + +private class ContentWrapper: Redwood_treehouseTreehouseViewContent { + + let treehouseUI: Redwood_treehouseZiplineTreehouseUi + + init(treehouseUI: Redwood_treehouseZiplineTreehouseUi) { + self.treehouseUI = treehouseUI + } + + func get(app: Any) -> Redwood_treehouseZiplineTreehouseUi { + return treehouseUI + } + + +} diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/TreehouseViewRenderer.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/TreehouseViewRenderer.swift new file mode 100644 index 0000000000..a9d33443ad --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/TreehouseViewRenderer.swift @@ -0,0 +1,16 @@ +// Copyright © Square, Inc. All rights reserved. + +import Foundation +import shared +import SwiftUI + +struct TreehouseViewRenderer: View { + + let treehouseView: Redwood_treehouseTreehouseSwiftUIView + + var body: some View { + ZStack { + WidgetChildrenView(children: treehouseView.children) + } + } +} diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenObserver.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenObserver.swift new file mode 100644 index 0000000000..3767cf22e3 --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenObserver.swift @@ -0,0 +1,19 @@ +// Copyright © Square, Inc. All rights reserved. + +import Foundation +import shared + +final class WidgetChildrenObserver: ObservableObject { + + let children: Redwood_widgetSwiftUIChildren + init(children: Redwood_widgetWidgetChildren) { + self.children = children as! Redwood_widgetSwiftUIChildren + self.children.observer = { [weak self] in + self?.objectWillChange.send() + } + } + + var widgets: [any Redwood_widgetWidget] { + children.widgets + } +} diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenView.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenView.swift new file mode 100644 index 0000000000..f184bf822c --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenView.swift @@ -0,0 +1,35 @@ +// Copyright © Square, Inc. All rights reserved. + +import Foundation +import SwiftUI +import shared + +// MARK: - Memory footprint + +struct WidgetChildrenView { + + @StateObject private var observer: WidgetChildrenObserver + + init(children: Redwood_widgetWidgetChildren) { + _observer = StateObject(wrappedValue: WidgetChildrenObserver(children: children)) + } +} + +// MARK: - Rendering + +extension WidgetChildrenView: View { + + var body: some View { + return ForEach(Array(observer.widgets.indices), id: \.self) { index in + childView(widget: observer.widgets[index]) + } + } + + private func childView(widget: Any) -> AnyView { + guard let child = widget as? any SwiftUIView else { + fatalError("Could not cast \(String(describing: widget)) as SwiftUIView") + } + return AnyView(child.view) + } + +} diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/EmojiSearchAppApp.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/EmojiSearchAppApp.swift deleted file mode 100644 index 193bb58167..0000000000 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/EmojiSearchAppApp.swift +++ /dev/null @@ -1,22 +0,0 @@ -// Created by Alexander skorulis on 1/12/2022. -// Copyright © Square, Inc. All rights reserved. - -import SwiftUI -import shared - -@main -struct EmojiSearchAppApp: App { - - private let urlSession: URLSession = .init(configuration: .default) - - init() { - let emojiSearchLauncher = EmojiSearchLauncher(nsurlSession: urlSession, hostApi: IosHostApi()) - let treehouseApp = emojiSearchLauncher.createTreehouseApp() - } - - var body: some Scene { - WindowGroup { - ContentView() - } - } -} diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Assets.xcassets/AccentColor.colorset/Contents.json b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Resource/Assets.xcassets/AccentColor.colorset/Contents.json similarity index 100% rename from samples/emoji-search/ios/swiftUI/EmojiSearchApp/Assets.xcassets/AccentColor.colorset/Contents.json rename to samples/emoji-search/ios/swiftUI/EmojiSearchApp/Resource/Assets.xcassets/AccentColor.colorset/Contents.json diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Assets.xcassets/AppIcon.appiconset/Contents.json b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Resource/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from samples/emoji-search/ios/swiftUI/EmojiSearchApp/Assets.xcassets/AppIcon.appiconset/Contents.json rename to samples/emoji-search/ios/swiftUI/EmojiSearchApp/Resource/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Assets.xcassets/Contents.json b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Resource/Assets.xcassets/Contents.json similarity index 100% rename from samples/emoji-search/ios/swiftUI/EmojiSearchApp/Assets.xcassets/Contents.json rename to samples/emoji-search/ios/swiftUI/EmojiSearchApp/Resource/Assets.xcassets/Contents.json diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Preview Content/Preview Assets.xcassets/Contents.json b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Resource/Preview Content/Preview Assets.xcassets/Contents.json similarity index 100% rename from samples/emoji-search/ios/swiftUI/EmojiSearchApp/Preview Content/Preview Assets.xcassets/Contents.json rename to samples/emoji-search/ios/swiftUI/EmojiSearchApp/Resource/Preview Content/Preview Assets.xcassets/Contents.json diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/ContentView.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/ContentView.swift new file mode 100644 index 0000000000..8faa146f59 --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/ContentView.swift @@ -0,0 +1,21 @@ +// Copyright © Square, Inc. All rights reserved. + +import SwiftUI + +struct ContentView: View { + + @StateObject var viewModel: ContentViewModel + + var body: some View { + TreehouseViewRenderer(treehouseView: viewModel.treehouseView) + .environment(\.treehouseApp, viewModel.treehouseApp) + .environment(\.treehouseWidgetSystem, viewModel.widgetSystem) + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + let viewModel = ContentViewModel() + ContentView(viewModel: viewModel) + } +} diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/ContentViewModel.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/ContentViewModel.swift new file mode 100644 index 0000000000..060cc1d8f0 --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/ContentViewModel.swift @@ -0,0 +1,27 @@ +// Copyright © Square, Inc. All rights reserved. + +import Foundation +import shared + +final class ContentViewModel: ObservableObject { + + private let urlSession: URLSession = .init(configuration: .default) + let treehouseView: Redwood_treehouseTreehouseSwiftUIView + + let treehouseApp: Redwood_treehouseTreehouseApp + let widgetSystem: EmojiSearchWidgetSystem + + init() { + let emojiSearchLauncher = EmojiSearchLauncher(nsurlSession: urlSession, hostApi: IosHostApi()) + treehouseApp = emojiSearchLauncher.createTreehouseApp() + widgetSystem = EmojiSearchWidgetSystem() + + treehouseView = Redwood_treehouseTreehouseSwiftUIView( + treehouseApp: treehouseApp, + widgetSystem: widgetSystem + ) + treehouseApp.renderTo(view: treehouseView) + treehouseView.setContent(content: EmojiSearchContent()) + } + +} diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/EmojiSearchApp.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/EmojiSearchApp.swift new file mode 100644 index 0000000000..641988c960 --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/EmojiSearchApp.swift @@ -0,0 +1,41 @@ +// Copyright © Square, Inc. All rights reserved. + +import SwiftUI +import shared + +@main +struct EmojiSearchApp: App { + + init() { + + } + + var body: some Scene { + WindowGroup { + ContentView(viewModel: ContentViewModel()) + } + } + +} + +class EmojiSearchContent : Redwood_treehouseTreehouseViewContent { + func get(app: Any) -> Redwood_treehouseZiplineTreehouseUi { + let treehouesUi = (app as! PresentersEmojiSearchPresenter) + return treehouesUi.launch() + } +} + + +class EmojiSearchWidgetSystem : Redwood_treehouseTreehouseViewWidgetSystem { + func widgetFactory(app: Redwood_treehouseTreehouseApp, + json: Kotlinx_serialization_jsonJson, + protocolMismatchHandler: Redwood_protocol_widgetProtocolMismatchHandler + ) -> Redwood_protocol_widgetDiffConsumingNodeFactory { + return ExposedKt.diffConsumingEmojiSearchWidgetFactory( + delegate: SwiftUIEmojiSearchWidgetFactory(treehouseApp: app, widgetSystem: self), + json: json, + mismatchHandler: protocolMismatchHandler + ); + } +} + diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Service/RemoteImageLoader.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Service/RemoteImageLoader.swift new file mode 100644 index 0000000000..c51c23c576 --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Service/RemoteImageLoader.swift @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2022 Square, Inc. + * + * 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 Foundation +import UIKit + +final class RemoteImageLoader { + + private var cache: [URL: UIImage] = [:] + + func loadImage(url: URL, completion: @escaping (URL, UIImage) -> Void) { + if let image = cache[url] { + completion(url, image) + return + } + + // This is not a good image loader, but it's a good-enough image loader. + DispatchQueue.global().async { [weak self] in + guard let data = try? Data(contentsOf: url) else { return } + guard let image = UIImage(data: data) else { return } + DispatchQueue.main.async { + self?.cache[url] = image + completion(url, image) + } + } + } +} diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift new file mode 100644 index 0000000000..85ca0fbb7c --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift @@ -0,0 +1,59 @@ +// Copyright © Square, Inc. All rights reserved. + +import Foundation +import shared +import SwiftUI + +final class ColumnBinding: WidgetColumn, SwiftUIView { + func height(height: Int32) { + + } + + func horizontalAlignment(horizontalAlignment: Int32) { + + } + + func overflow(overflow: Int32) { + + } + + func padding(padding: Redwood_layout_apiPadding) { + + } + + func verticalAlignment(verticalAlignment: Int32) { + + } + + func width(width: Int32) { + + } + + var children: Redwood_widgetWidgetChildren! + + var layoutModifiers: Redwood_runtimeLayoutModifier = ExposedKt.layoutModifier() + + var value: Any { NSNull() } + + var view: some View { ColumnView(binding: self) } + + init() { + self.children = Redwood_widgetSwiftUIChildren(parent: self) + } + +} + + +struct ColumnView: View { + + @ObservedObject var binding: ColumnBinding + + var body: some View { + ScrollView { + VStack(spacing: 0) { + WidgetChildrenView(children: binding.children) + } + } + } + +} diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ImageBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ImageBinding.swift new file mode 100644 index 0000000000..e913ca86c8 --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ImageBinding.swift @@ -0,0 +1,38 @@ +// Copyright © Square, Inc. All rights reserved. + +import Foundation +import shared +import SwiftUI + +final class ImageBinding: WidgetImage, SwiftUIView { + + @Published var url: String = "" + + func url(url: String) { + self.url = url + } + + var layoutModifiers: Redwood_runtimeLayoutModifier = ExposedKt.layoutModifier() + var view: some View { ImageView(binding: self) } + var value: Any { NSNull() } + +} + +struct ImageView: View { + + @ObservedObject var binding: ImageBinding + + var body: some View { + content + .id(binding.url) + } + + @ViewBuilder + private var content: some View { + if let url = URL(string: binding.url) { + AsyncImage(url: url) + } else { + EmptyView() + } + } +} diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/LazyColumnBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/LazyColumnBinding.swift new file mode 100644 index 0000000000..0545fae43e --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/LazyColumnBinding.swift @@ -0,0 +1,52 @@ +// Copyright © Square, Inc. All rights reserved. + +import Foundation +import shared +import SwiftUI + +final class LazyColumnBinding: WidgetLazyColumn, SwiftUIView { + + @Published var intervals: [Redwood_treehouse_lazylayout_apiLazyListIntervalContent] = [] + @Published fileprivate var randomID: String = "" + + func intervals(intervals: [Redwood_treehouse_lazylayout_apiLazyListIntervalContent]) { + self.intervals = intervals + self.randomID = UUID().uuidString + } + + var layoutModifiers: Redwood_runtimeLayoutModifier = ExposedKt.layoutModifier() + + var view: some View { LazyColumnView(binding: self) } + var value: Any { NSNull() } +} + +struct LazyColumnView: View { + + @ObservedObject var binding: LazyColumnBinding + + @Environment(\.treehouseApp) private var treehouseApp + @Environment(\.treehouseWidgetSystem) private var treehouseWidgetSystem + + var body: some View { + LazyVStack { + ForEach(Array(binding.intervals.indices), id: \.self) { index in + let interval = binding.intervals[index] + ForEach(Array(0.. Void)? + private var userEditCount: Int64 = 0 + + func hint(hint: String) { + self.hint = hint + } + + func onChange(onChange: ((ValuesTextFieldState) -> Void)? = nil) { + self.onChange = onChange + } + + func state(state: ValuesTextFieldState) { + if self.text != state.text && state.userEditCount >= self.userEditCount { + self.text = state.text + self.userEditCount = state.userEditCount + } + } + + var layoutModifiers: Redwood_runtimeLayoutModifier = ExposedKt.layoutModifier() + var view: some View { TextInputView(binding: self) } + var value: Any { NSNull() } + + var textBinding: Binding { + return Binding { [unowned self] in + return self.text + } set: { [unowned self] newValue in + if newValue != self.text { + self.text = newValue + self.userEditCount += 1 + let state = ValuesTextFieldState( + text: newValue, + selectionStart: 0, + selectionEnd: 0, + userEditCount: self.userEditCount + ) + self.onChange?(state) + } + } + } + +} + +struct TextInputView: View { + + @ObservedObject var binding: TextInputBinding + + var body: some View { + TextField(binding.hint, text: binding.textBinding) + } + +} + diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUIEmojiSearchWidgetFactory.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUIEmojiSearchWidgetFactory.swift new file mode 100644 index 0000000000..ce2740c726 --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUIEmojiSearchWidgetFactory.swift @@ -0,0 +1,24 @@ +// Copyright © Square, Inc. All rights reserved. + +import Foundation +import shared +import SwiftUI + +class SwiftUIEmojiSearchWidgetFactory: WidgetEmojiSearchWidgetFactory { + let treehouseApp: Redwood_treehouseTreehouseApp + let widgetSystem: Redwood_treehouseTreehouseViewWidgetSystem + let imageLoader = RemoteImageLoader() + + var RedwoodLayout: WidgetRedwoodLayoutWidgetFactory = SwiftUILayoutWidgetFactory() + var RedwoodTreehouseLazyLayout: WidgetRedwoodTreehouseLazyLayoutWidgetFactory + + init(treehouseApp: Redwood_treehouseTreehouseApp, widgetSystem: Redwood_treehouseTreehouseViewWidgetSystem) { + self.treehouseApp = treehouseApp + self.widgetSystem = widgetSystem + self.RedwoodTreehouseLazyLayout = SwiftUILazyLayoutWidgetFactory() + } + + func TextInput() -> WidgetTextInput { TextInputBinding() } + func Text() -> WidgetText { TextBinding() } + func Image() -> WidgetImage { ImageBinding() } +} diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUILayoutWidgetFactory.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUILayoutWidgetFactory.swift new file mode 100644 index 0000000000..9c430398f1 --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUILayoutWidgetFactory.swift @@ -0,0 +1,11 @@ +// Copyright © Square, Inc. All rights reserved. + +import Foundation +import shared + +final class SwiftUILayoutWidgetFactory: WidgetRedwoodLayoutWidgetFactory { + func Column() -> WidgetColumn { ColumnBinding() } + func Row() -> WidgetRow { RowBinding() } + + +} diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUILazyLayoutWidgetFactory.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUILazyLayoutWidgetFactory.swift new file mode 100644 index 0000000000..8b7bfca7d2 --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUILazyLayoutWidgetFactory.swift @@ -0,0 +1,11 @@ +// Copyright © Square, Inc. All rights reserved. + +import Foundation +import shared + +class SwiftUILazyLayoutWidgetFactory: WidgetRedwoodTreehouseLazyLayoutWidgetFactory { + func LazyColumn() -> WidgetLazyColumn { + LazyColumnBinding() + } + +} From f96a2344c1985be5ae8467dbf5b84bb9fa4abc62 Mon Sep 17 00:00:00 2001 From: Alex Skorulis Date: Tue, 6 Dec 2022 11:28:16 +1100 Subject: [PATCH 03/13] Update documentation --- samples/emoji-search/ios/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/samples/emoji-search/ios/README.md b/samples/emoji-search/ios/README.md index b72a7a0fcc..b2b04574c3 100644 --- a/samples/emoji-search/ios/README.md +++ b/samples/emoji-search/ios/README.md @@ -1,3 +1,9 @@ # iOS Emoji Search In `app/`, run `pod install` and then `open EmojiSearchApp.xcworkspace/`. + +# SwiftUI + +The same app has also been built in SwiftUI + +In `swiftUI/`, run `pod install` and then `open EmojiSearchApp.xcworkspace/`. From cadf920b9376e014bc66380358bcec873f86a7d4 Mon Sep 17 00:00:00 2001 From: Alex Skorulis Date: Tue, 6 Dec 2022 11:37:58 +1100 Subject: [PATCH 04/13] Improve identity --- samples/emoji-search/ios/README.md | 2 +- .../ios/swiftUI/EmojiSearchApp/Core/SwiftUIView.swift | 3 +++ .../EmojiSearchApp/Core/WidgetChildrenObserver.swift | 9 +++++++++ .../EmojiSearchApp/Core/WidgetChildrenView.swift | 11 ++++------- .../swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift | 4 ++-- .../swiftUI/EmojiSearchApp/Widget/ImageBinding.swift | 2 +- .../EmojiSearchApp/Widget/LazyColumnBinding.swift | 2 +- .../swiftUI/EmojiSearchApp/Widget/RowBinding.swift | 2 +- .../swiftUI/EmojiSearchApp/Widget/TextBinding.swift | 2 +- .../EmojiSearchApp/Widget/TextInputBinding.swift | 2 +- 10 files changed, 24 insertions(+), 15 deletions(-) diff --git a/samples/emoji-search/ios/README.md b/samples/emoji-search/ios/README.md index b2b04574c3..3fea9de312 100644 --- a/samples/emoji-search/ios/README.md +++ b/samples/emoji-search/ios/README.md @@ -4,6 +4,6 @@ In `app/`, run `pod install` and then `open EmojiSearchApp.xcworkspace/`. # SwiftUI -The same app has also been built in SwiftUI +The same app has also been built in SwiftUI. In `swiftUI/`, run `pod install` and then `open EmojiSearchApp.xcworkspace/`. diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/SwiftUIView.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/SwiftUIView.swift index d794578b8c..6bf384955e 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/SwiftUIView.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/SwiftUIView.swift @@ -8,5 +8,8 @@ protocol SwiftUIView: Redwood_widgetSwiftUIView, ObservableObject { associatedtype ViewType: View @ViewBuilder var view: ViewType { get } + + // Conform classes to Identifiable to get this conformance + var id: ObjectIdentifier { get } } diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenObserver.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenObserver.swift index 3767cf22e3..f75f913307 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenObserver.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenObserver.swift @@ -16,4 +16,13 @@ final class WidgetChildrenObserver: ObservableObject { var widgets: [any Redwood_widgetWidget] { children.widgets } + + var swiftUIWidgets: [any SwiftUIView] { + return children.widgets.map { widget in + guard let swiftUIWidget = widget as? any SwiftUIView else { + fatalError("Could not cast \(String(describing: widget)) as SwiftUIView") + } + return swiftUIWidget + } + } } diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenView.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenView.swift index f184bf822c..cf0b216ad2 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenView.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenView.swift @@ -20,16 +20,13 @@ struct WidgetChildrenView { extension WidgetChildrenView: View { var body: some View { - return ForEach(Array(observer.widgets.indices), id: \.self) { index in - childView(widget: observer.widgets[index]) + return ForEach(observer.swiftUIWidgets, id: \.self.id) { widget in + childView(widget: widget) } } - private func childView(widget: Any) -> AnyView { - guard let child = widget as? any SwiftUIView else { - fatalError("Could not cast \(String(describing: widget)) as SwiftUIView") - } - return AnyView(child.view) + private func childView(widget: any SwiftUIView) -> AnyView { + return AnyView(widget.view) } } diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift index 85ca0fbb7c..40e6195e93 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift @@ -4,9 +4,9 @@ import Foundation import shared import SwiftUI -final class ColumnBinding: WidgetColumn, SwiftUIView { +final class ColumnBinding: WidgetColumn, SwiftUIView, Identifiable { func height(height: Int32) { - + } func horizontalAlignment(horizontalAlignment: Int32) { diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ImageBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ImageBinding.swift index e913ca86c8..1adba71c12 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ImageBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ImageBinding.swift @@ -4,7 +4,7 @@ import Foundation import shared import SwiftUI -final class ImageBinding: WidgetImage, SwiftUIView { +final class ImageBinding: WidgetImage, SwiftUIView, Identifiable { @Published var url: String = "" diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/LazyColumnBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/LazyColumnBinding.swift index 0545fae43e..e80c2500f5 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/LazyColumnBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/LazyColumnBinding.swift @@ -4,7 +4,7 @@ import Foundation import shared import SwiftUI -final class LazyColumnBinding: WidgetLazyColumn, SwiftUIView { +final class LazyColumnBinding: WidgetLazyColumn, SwiftUIView, Identifiable { @Published var intervals: [Redwood_treehouse_lazylayout_apiLazyListIntervalContent] = [] @Published fileprivate var randomID: String = "" diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/RowBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/RowBinding.swift index 9dc03d9eba..dd3df6154b 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/RowBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/RowBinding.swift @@ -4,7 +4,7 @@ import Foundation import shared import SwiftUI -final class RowBinding: WidgetRow, SwiftUIView { +final class RowBinding: WidgetRow, SwiftUIView, Identifiable { func height(height: Int32) { } diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextBinding.swift index b9f9a2f473..22647fc092 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextBinding.swift @@ -4,7 +4,7 @@ import Foundation import shared import SwiftUI -final class TextBinding: WidgetText, SwiftUIView { +final class TextBinding: WidgetText, SwiftUIView, Identifiable { @Published var text: String = "" diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextInputBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextInputBinding.swift index 0ee690d872..1fa8da47da 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextInputBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextInputBinding.swift @@ -6,7 +6,7 @@ import SwiftUI // MARK: - Memory footprint -final class TextInputBinding: WidgetTextInput, SwiftUIView { +final class TextInputBinding: WidgetTextInput, SwiftUIView, Identifiable { @Published var hint: String = "" @Published var text: String = "" From 5b0d2c1790c61d672a0b8389163a1632f831feab Mon Sep 17 00:00:00 2001 From: Alex Skorulis Date: Tue, 6 Dec 2022 12:04:05 +1100 Subject: [PATCH 05/13] Simplify code --- .../EmojiSearchApp.xcodeproj/project.pbxproj | 14 +++++++++----- ...{SwiftUIView.swift => SwiftUIViewBinding.swift} | 4 ++-- .../Core/WidgetChildrenObserver.swift | 4 ++-- .../EmojiSearchApp/Core/WidgetChildrenView.swift | 2 +- .../swiftUI/EmojiSearchApp/Widget/BaseWidget.swift | 11 +++++++++++ .../EmojiSearchApp/Widget/ColumnBinding.swift | 9 +++------ .../EmojiSearchApp/Widget/ImageBinding.swift | 6 ++---- .../EmojiSearchApp/Widget/LazyColumnBinding.swift | 5 +---- .../swiftUI/EmojiSearchApp/Widget/RowBinding.swift | 8 +++----- .../EmojiSearchApp/Widget/TextBinding.swift | 4 +--- .../EmojiSearchApp/Widget/TextInputBinding.swift | 4 +--- 11 files changed, 36 insertions(+), 35 deletions(-) rename samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/{SwiftUIView.swift => SwiftUIViewBinding.swift} (63%) create mode 100644 samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/BaseWidget.swift diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp.xcodeproj/project.pbxproj b/samples/emoji-search/ios/swiftUI/EmojiSearchApp.xcodeproj/project.pbxproj index dd861dc4e3..5be32f348d 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp.xcodeproj/project.pbxproj +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp.xcodeproj/project.pbxproj @@ -3,11 +3,12 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 56; objects = { /* Begin PBXBuildFile section */ 320A9E3134B16AB401CAB3B3 /* Pods_EmojiSearchApp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2B340877E75215F2AED9BA8 /* Pods_EmojiSearchApp.framework */; }; + C46C9E50293ECB3200AD7E1E /* BaseWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46C9E4F293ECB3200AD7E1E /* BaseWidget.swift */; }; C4A7515E2938598D00D3F831 /* IosHostApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A7515D2938598D00D3F831 /* IosHostApi.swift */; }; C4A751672938674300D3F831 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C4A751642938674300D3F831 /* Assets.xcassets */; }; C4A751682938674300D3F831 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C4A751662938674300D3F831 /* Preview Assets.xcassets */; }; @@ -15,7 +16,7 @@ C4A7516E2938734100D3F831 /* SwiftUIEmojiSearchWidgetFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A7516D2938734100D3F831 /* SwiftUIEmojiSearchWidgetFactory.swift */; }; C4A751702938734700D3F831 /* SwiftUILayoutWidgetFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A7516F2938734700D3F831 /* SwiftUILayoutWidgetFactory.swift */; }; C4A75172293873E700D3F831 /* ColumnBinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A75171293873E700D3F831 /* ColumnBinding.swift */; }; - FA42CB27293C34DE00031CF0 /* SwiftUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA42CB26293C34DE00031CF0 /* SwiftUIView.swift */; }; + FA42CB27293C34DE00031CF0 /* SwiftUIViewBinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA42CB26293C34DE00031CF0 /* SwiftUIViewBinding.swift */; }; FA42CB29293C350200031CF0 /* WidgetChildrenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA42CB28293C350200031CF0 /* WidgetChildrenView.swift */; }; FA42CB2B293C361100031CF0 /* WidgetChildrenObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA42CB2A293C361100031CF0 /* WidgetChildrenObserver.swift */; }; FA42CB2D293C3A4C00031CF0 /* LazyColumnBinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA42CB2C293C3A4C00031CF0 /* LazyColumnBinding.swift */; }; @@ -35,6 +36,7 @@ /* Begin PBXFileReference section */ 8D728DFB15C556F9D94C2A56 /* Pods-EmojiSearchApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-EmojiSearchApp.release.xcconfig"; path = "Target Support Files/Pods-EmojiSearchApp/Pods-EmojiSearchApp.release.xcconfig"; sourceTree = ""; }; B1676165A1782330A65CC380 /* Pods-EmojiSearchApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-EmojiSearchApp.debug.xcconfig"; path = "Target Support Files/Pods-EmojiSearchApp/Pods-EmojiSearchApp.debug.xcconfig"; sourceTree = ""; }; + C46C9E4F293ECB3200AD7E1E /* BaseWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseWidget.swift; sourceTree = ""; }; C4A7512F2938580300D3F831 /* EmojiSearchApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = EmojiSearchApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; C4A7515D2938598D00D3F831 /* IosHostApi.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IosHostApi.swift; sourceTree = ""; }; C4A751642938674300D3F831 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -44,7 +46,7 @@ C4A7516F2938734700D3F831 /* SwiftUILayoutWidgetFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUILayoutWidgetFactory.swift; sourceTree = ""; }; C4A75171293873E700D3F831 /* ColumnBinding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColumnBinding.swift; sourceTree = ""; }; D2B340877E75215F2AED9BA8 /* Pods_EmojiSearchApp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_EmojiSearchApp.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - FA42CB26293C34DE00031CF0 /* SwiftUIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftUIView.swift; sourceTree = ""; }; + FA42CB26293C34DE00031CF0 /* SwiftUIViewBinding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftUIViewBinding.swift; sourceTree = ""; }; FA42CB28293C350200031CF0 /* WidgetChildrenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetChildrenView.swift; sourceTree = ""; }; FA42CB2A293C361100031CF0 /* WidgetChildrenObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetChildrenObserver.swift; sourceTree = ""; }; FA42CB2C293C3A4C00031CF0 /* LazyColumnBinding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LazyColumnBinding.swift; sourceTree = ""; }; @@ -148,6 +150,7 @@ FA42CB3D293C529B00031CF0 /* RowBinding.swift */, FA42CB3F293C540800031CF0 /* ImageBinding.swift */, FA42CB41293C556900031CF0 /* TextBinding.swift */, + C46C9E4F293ECB3200AD7E1E /* BaseWidget.swift */, ); path = Widget; sourceTree = ""; @@ -173,7 +176,7 @@ FA42CB25293C34CF00031CF0 /* Core */ = { isa = PBXGroup; children = ( - FA42CB26293C34DE00031CF0 /* SwiftUIView.swift */, + FA42CB26293C34DE00031CF0 /* SwiftUIViewBinding.swift */, FA42CB28293C350200031CF0 /* WidgetChildrenView.swift */, FA42CB2A293C361100031CF0 /* WidgetChildrenObserver.swift */, FA42CB30293C413500031CF0 /* EnvironmentKeys.swift */, @@ -294,9 +297,10 @@ FA42CB3C293C471100031CF0 /* ContentView.swift in Sources */, FA42CB40293C540800031CF0 /* ImageBinding.swift in Sources */, FA42CB35293C46FC00031CF0 /* RemoteImageLoader.swift in Sources */, - FA42CB27293C34DE00031CF0 /* SwiftUIView.swift in Sources */, + FA42CB27293C34DE00031CF0 /* SwiftUIViewBinding.swift in Sources */, FA42CB3A293C471100031CF0 /* EmojiSearchApp.swift in Sources */, C4A7516E2938734100D3F831 /* SwiftUIEmojiSearchWidgetFactory.swift in Sources */, + C46C9E50293ECB3200AD7E1E /* BaseWidget.swift in Sources */, C4A7515E2938598D00D3F831 /* IosHostApi.swift in Sources */, FA42CB2B293C361100031CF0 /* WidgetChildrenObserver.swift in Sources */, FA42CB29293C350200031CF0 /* WidgetChildrenView.swift in Sources */, diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/SwiftUIView.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/SwiftUIViewBinding.swift similarity index 63% rename from samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/SwiftUIView.swift rename to samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/SwiftUIViewBinding.swift index 6bf384955e..842e8574a4 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/SwiftUIView.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/SwiftUIViewBinding.swift @@ -4,12 +4,12 @@ import Foundation import shared import SwiftUI -protocol SwiftUIView: Redwood_widgetSwiftUIView, ObservableObject { +protocol SwiftUIViewBinding: Redwood_widgetSwiftUIView, ObservableObject { associatedtype ViewType: View @ViewBuilder var view: ViewType { get } - // Conform classes to Identifiable to get this conformance + // This gets automatic conformance in BaseWidget var id: ObjectIdentifier { get } } diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenObserver.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenObserver.swift index f75f913307..10b8c2183a 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenObserver.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenObserver.swift @@ -17,9 +17,9 @@ final class WidgetChildrenObserver: ObservableObject { children.widgets } - var swiftUIWidgets: [any SwiftUIView] { + var swiftUIWidgets: [any SwiftUIViewBinding] { return children.widgets.map { widget in - guard let swiftUIWidget = widget as? any SwiftUIView else { + guard let swiftUIWidget = widget as? any SwiftUIViewBinding else { fatalError("Could not cast \(String(describing: widget)) as SwiftUIView") } return swiftUIWidget diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenView.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenView.swift index cf0b216ad2..024bfa9202 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenView.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenView.swift @@ -25,7 +25,7 @@ extension WidgetChildrenView: View { } } - private func childView(widget: any SwiftUIView) -> AnyView { + private func childView(widget: any SwiftUIViewBinding) -> AnyView { return AnyView(widget.view) } diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/BaseWidget.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/BaseWidget.swift new file mode 100644 index 0000000000..9ccc413e20 --- /dev/null +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/BaseWidget.swift @@ -0,0 +1,11 @@ +// Copyright © Square, Inc. All rights reserved. + +import Foundation +import shared + +class BaseWidget: NSObject, Identifiable { + + @objc var value: Any { NSNull() } + @objc var layoutModifiers: Redwood_runtimeLayoutModifier = ExposedKt.layoutModifier() + +} diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift index 40e6195e93..bb50553208 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift @@ -4,7 +4,7 @@ import Foundation import shared import SwiftUI -final class ColumnBinding: WidgetColumn, SwiftUIView, Identifiable { +final class ColumnBinding: BaseWidget, WidgetColumn, SwiftUIViewBinding { func height(height: Int32) { } @@ -30,14 +30,11 @@ final class ColumnBinding: WidgetColumn, SwiftUIView, Identifiable { } var children: Redwood_widgetWidgetChildren! - - var layoutModifiers: Redwood_runtimeLayoutModifier = ExposedKt.layoutModifier() - - var value: Any { NSNull() } var view: some View { ColumnView(binding: self) } - init() { + override init() { + super.init() self.children = Redwood_widgetSwiftUIChildren(parent: self) } diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ImageBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ImageBinding.swift index 1adba71c12..433aa51ddb 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ImageBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ImageBinding.swift @@ -4,17 +4,15 @@ import Foundation import shared import SwiftUI -final class ImageBinding: WidgetImage, SwiftUIView, Identifiable { +final class ImageBinding: BaseWidget, WidgetImage, SwiftUIViewBinding { @Published var url: String = "" func url(url: String) { self.url = url } - - var layoutModifiers: Redwood_runtimeLayoutModifier = ExposedKt.layoutModifier() + var view: some View { ImageView(binding: self) } - var value: Any { NSNull() } } diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/LazyColumnBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/LazyColumnBinding.swift index e80c2500f5..15fc8ec11e 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/LazyColumnBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/LazyColumnBinding.swift @@ -4,7 +4,7 @@ import Foundation import shared import SwiftUI -final class LazyColumnBinding: WidgetLazyColumn, SwiftUIView, Identifiable { +final class LazyColumnBinding: BaseWidget, WidgetLazyColumn, SwiftUIViewBinding { @Published var intervals: [Redwood_treehouse_lazylayout_apiLazyListIntervalContent] = [] @Published fileprivate var randomID: String = "" @@ -14,10 +14,7 @@ final class LazyColumnBinding: WidgetLazyColumn, SwiftUIView, Identifiable { self.randomID = UUID().uuidString } - var layoutModifiers: Redwood_runtimeLayoutModifier = ExposedKt.layoutModifier() - var view: some View { LazyColumnView(binding: self) } - var value: Any { NSNull() } } struct LazyColumnView: View { diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/RowBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/RowBinding.swift index dd3df6154b..a58a4935c5 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/RowBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/RowBinding.swift @@ -4,7 +4,7 @@ import Foundation import shared import SwiftUI -final class RowBinding: WidgetRow, SwiftUIView, Identifiable { +final class RowBinding: BaseWidget, WidgetRow, SwiftUIViewBinding { func height(height: Int32) { } @@ -30,12 +30,10 @@ final class RowBinding: WidgetRow, SwiftUIView, Identifiable { } var children: Redwood_widgetWidgetChildren! - var value: Any { NSNull() } var view: some View { RowView(binding: self) } - var layoutModifiers: Redwood_runtimeLayoutModifier = ExposedKt.layoutModifier() - - init() { + override init() { + super.init() self.children = Redwood_widgetSwiftUIChildren(parent: self) } diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextBinding.swift index 22647fc092..3f8e53f790 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextBinding.swift @@ -4,7 +4,7 @@ import Foundation import shared import SwiftUI -final class TextBinding: WidgetText, SwiftUIView, Identifiable { +final class TextBinding: BaseWidget, WidgetText, SwiftUIViewBinding { @Published var text: String = "" @@ -13,8 +13,6 @@ final class TextBinding: WidgetText, SwiftUIView, Identifiable { } var view: some View { TextView(binding: self) } - var value: Any { NSNull() } - var layoutModifiers: Redwood_runtimeLayoutModifier = ExposedKt.layoutModifier() } diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextInputBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextInputBinding.swift index 1fa8da47da..a632be9873 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextInputBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextInputBinding.swift @@ -6,7 +6,7 @@ import SwiftUI // MARK: - Memory footprint -final class TextInputBinding: WidgetTextInput, SwiftUIView, Identifiable { +final class TextInputBinding: BaseWidget, WidgetTextInput, SwiftUIViewBinding { @Published var hint: String = "" @Published var text: String = "" @@ -29,9 +29,7 @@ final class TextInputBinding: WidgetTextInput, SwiftUIView, Identifiable { } } - var layoutModifiers: Redwood_runtimeLayoutModifier = ExposedKt.layoutModifier() var view: some View { TextInputView(binding: self) } - var value: Any { NSNull() } var textBinding: Binding { return Binding { [unowned self] in From d5bfd74dd7319877d5a70c82cdbbabdea1a554b4 Mon Sep 17 00:00:00 2001 From: Alex Skorulis Date: Tue, 6 Dec 2022 13:25:59 +1100 Subject: [PATCH 06/13] Fix build warnings --- .../kotlin/app/cash/redwood/widget/SwiftUIChildren.kt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/redwood-widget/src/iosMain/kotlin/app/cash/redwood/widget/SwiftUIChildren.kt b/redwood-widget/src/iosMain/kotlin/app/cash/redwood/widget/SwiftUIChildren.kt index a9c429068b..55f8c4722e 100644 --- a/redwood-widget/src/iosMain/kotlin/app/cash/redwood/widget/SwiftUIChildren.kt +++ b/redwood-widget/src/iosMain/kotlin/app/cash/redwood/widget/SwiftUIChildren.kt @@ -15,12 +15,7 @@ */ package app.cash.redwood.widget -import kotlinx.cinterop.convert -import platform.darwin.NSInteger - -public interface SwiftUIView { - -} +public interface SwiftUIView public class SwiftUIChildren( private val parent: SwiftUIView, @@ -48,5 +43,4 @@ public class SwiftUIChildren( override fun onLayoutModifierUpdated(index: Int) { // TODO } - } From cd1428cf2a3851739272c84d4021e48a0b85fe09 Mon Sep 17 00:00:00 2001 From: Alex Skorulis Date: Tue, 6 Dec 2022 14:08:04 +1100 Subject: [PATCH 07/13] Fix up compiler instability issues --- .../cash/redwood/treehouse/TreehouseSwiftUIView.kt | 2 -- .../EmojiSearchApp/Core/WidgetChildrenObserver.swift | 9 +-------- .../EmojiSearchApp/Core/WidgetChildrenView.swift | 12 +++++++++++- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/redwood-treehouse/src/iosMain/kotlin/app/cash/redwood/treehouse/TreehouseSwiftUIView.kt b/redwood-treehouse/src/iosMain/kotlin/app/cash/redwood/treehouse/TreehouseSwiftUIView.kt index 97d80848fb..759fdbd638 100644 --- a/redwood-treehouse/src/iosMain/kotlin/app/cash/redwood/treehouse/TreehouseSwiftUIView.kt +++ b/redwood-treehouse/src/iosMain/kotlin/app/cash/redwood/treehouse/TreehouseSwiftUIView.kt @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package app.cash.redwood.treehouse import app.cash.redwood.treehouse.TreehouseView.CodeListener @@ -52,5 +51,4 @@ public class TreehouseSwiftUIView( this.content = content stateChangeListener?.onStateChanged(this) } - } diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenObserver.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenObserver.swift index 10b8c2183a..b166d5bb76 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenObserver.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenObserver.swift @@ -6,6 +6,7 @@ import shared final class WidgetChildrenObserver: ObservableObject { let children: Redwood_widgetSwiftUIChildren + init(children: Redwood_widgetWidgetChildren) { self.children = children as! Redwood_widgetSwiftUIChildren self.children.observer = { [weak self] in @@ -17,12 +18,4 @@ final class WidgetChildrenObserver: ObservableObject { children.widgets } - var swiftUIWidgets: [any SwiftUIViewBinding] { - return children.widgets.map { widget in - guard let swiftUIWidget = widget as? any SwiftUIViewBinding else { - fatalError("Could not cast \(String(describing: widget)) as SwiftUIView") - } - return swiftUIWidget - } - } } diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenView.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenView.swift index 024bfa9202..a6372e9da4 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenView.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenView.swift @@ -20,7 +20,7 @@ struct WidgetChildrenView { extension WidgetChildrenView: View { var body: some View { - return ForEach(observer.swiftUIWidgets, id: \.self.id) { widget in + ForEach(swiftUIWidgets, id: \.self.id) { widget in childView(widget: widget) } } @@ -28,5 +28,15 @@ extension WidgetChildrenView: View { private func childView(widget: any SwiftUIViewBinding) -> AnyView { return AnyView(widget.view) } + + // This causes compilation issues when inside the observer + private var swiftUIWidgets: [any SwiftUIViewBinding] { + return observer.widgets.map { widget in + guard let swiftUIWidget = widget as? any SwiftUIViewBinding else { + fatalError("Could not cast \(String(describing: widget)) as SwiftUIView") + } + return swiftUIWidget + } + } } From 67dd8983eed65ec7a29df024f27c4ec969eb7bea Mon Sep 17 00:00:00 2001 From: Alex Skorulis Date: Tue, 6 Dec 2022 21:42:49 +1100 Subject: [PATCH 08/13] Use RemoteImageLoader in ImageBinding Remove parent from SwiftUIChildren --- .../redwood/treehouse/TreehouseSwiftUIView.kt | 2 +- .../cash/redwood/widget/SwiftUIChildren.kt | 4 +-- .../EmojiSearchApp/Widget/ColumnBinding.swift | 7 +---- .../EmojiSearchApp/Widget/ImageBinding.swift | 27 +++++++++++++++---- .../EmojiSearchApp/Widget/RowBinding.swift | 10 ++----- .../SwiftUIEmojiSearchWidgetFactory.swift | 2 +- 6 files changed, 28 insertions(+), 24 deletions(-) diff --git a/redwood-treehouse/src/iosMain/kotlin/app/cash/redwood/treehouse/TreehouseSwiftUIView.kt b/redwood-treehouse/src/iosMain/kotlin/app/cash/redwood/treehouse/TreehouseSwiftUIView.kt index 759fdbd638..d99e80920e 100644 --- a/redwood-treehouse/src/iosMain/kotlin/app/cash/redwood/treehouse/TreehouseSwiftUIView.kt +++ b/redwood-treehouse/src/iosMain/kotlin/app/cash/redwood/treehouse/TreehouseSwiftUIView.kt @@ -30,7 +30,7 @@ public class TreehouseSwiftUIView( public override var codeListener: CodeListener = CodeListener() private var content: TreehouseView.Content? = null - private val _children = SwiftUIChildren(this) + private val _children = SwiftUIChildren() override val children: Widget.Children<*> = _children public override var stateChangeListener: TreehouseView.OnStateChangeListener? = null diff --git a/redwood-widget/src/iosMain/kotlin/app/cash/redwood/widget/SwiftUIChildren.kt b/redwood-widget/src/iosMain/kotlin/app/cash/redwood/widget/SwiftUIChildren.kt index 55f8c4722e..a5faa4e774 100644 --- a/redwood-widget/src/iosMain/kotlin/app/cash/redwood/widget/SwiftUIChildren.kt +++ b/redwood-widget/src/iosMain/kotlin/app/cash/redwood/widget/SwiftUIChildren.kt @@ -17,9 +17,7 @@ package app.cash.redwood.widget public interface SwiftUIView -public class SwiftUIChildren( - private val parent: SwiftUIView, -) : Widget.Children { +public class SwiftUIChildren() : Widget.Children { private val _widgets = MutableListChildren() public val widgets: List> = _widgets diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift index bb50553208..df3d5badba 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift @@ -29,14 +29,9 @@ final class ColumnBinding: BaseWidget, WidgetColumn, SwiftUIViewBinding { } - var children: Redwood_widgetWidgetChildren! + let children: Redwood_widgetWidgetChildren = Redwood_widgetSwiftUIChildren() var view: some View { ColumnView(binding: self) } - - override init() { - super.init() - self.children = Redwood_widgetSwiftUIChildren(parent: self) - } } diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ImageBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ImageBinding.swift index 433aa51ddb..c238550b13 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ImageBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ImageBinding.swift @@ -6,14 +6,32 @@ import SwiftUI final class ImageBinding: BaseWidget, WidgetImage, SwiftUIViewBinding { - @Published var url: String = "" + @Published var lastURL: URL? + @Published var image: UIImage? = nil + + let imageLoader: RemoteImageLoader func url(url: String) { - self.url = url + image = nil + guard let url = URL(string: url) else { + return + } + + lastURL = url + imageLoader.loadImage(url: url) { [unowned self] url, image in + guard self.lastURL == url else { + return + } + + self.image = image + } } var view: some View { ImageView(binding: self) } + init(imageLoader: RemoteImageLoader) { + self.imageLoader = imageLoader + } } struct ImageView: View { @@ -22,13 +40,12 @@ struct ImageView: View { var body: some View { content - .id(binding.url) } @ViewBuilder private var content: some View { - if let url = URL(string: binding.url) { - AsyncImage(url: url) + if let image = binding.image { + Image(uiImage: image) } else { EmptyView() } diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/RowBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/RowBinding.swift index a58a4935c5..83c19e2cc8 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/RowBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/RowBinding.swift @@ -29,15 +29,9 @@ final class RowBinding: BaseWidget, WidgetRow, SwiftUIViewBinding { } - var children: Redwood_widgetWidgetChildren! + let children: Redwood_widgetWidgetChildren = Redwood_widgetSwiftUIChildren() var view: some View { RowView(binding: self) } - - override init() { - super.init() - self.children = Redwood_widgetSwiftUIChildren(parent: self) - } - - + } struct RowView: View { diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUIEmojiSearchWidgetFactory.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUIEmojiSearchWidgetFactory.swift index ce2740c726..88d109db3d 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUIEmojiSearchWidgetFactory.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUIEmojiSearchWidgetFactory.swift @@ -20,5 +20,5 @@ class SwiftUIEmojiSearchWidgetFactory: WidgetEmojiSearchWidgetFac func TextInput() -> WidgetTextInput { TextInputBinding() } func Text() -> WidgetText { TextBinding() } - func Image() -> WidgetImage { ImageBinding() } + func Image() -> WidgetImage { ImageBinding(imageLoader: imageLoader) } } From 5c0edfea00f51f4737ea47046b6a5558cca6d85e Mon Sep 17 00:00:00 2001 From: Alex Skorulis Date: Mon, 12 Dec 2022 14:02:36 +1100 Subject: [PATCH 09/13] Fix issues after merge --- .../app/cash/redwood/treehouse/TreehouseSwiftUIView.kt | 2 +- .../swiftUI/EmojiSearchApp.xcodeproj/project.pbxproj | 2 +- .../EmojiSearchApp/Core/TreehouseUIRenderer.swift | 2 +- .../swiftUI/EmojiSearchApp/Scene/EmojiSearchApp.swift | 10 +++++----- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/redwood-treehouse/src/iosMain/kotlin/app/cash/redwood/treehouse/TreehouseSwiftUIView.kt b/redwood-treehouse/src/iosMain/kotlin/app/cash/redwood/treehouse/TreehouseSwiftUIView.kt index d99e80920e..43512805b7 100644 --- a/redwood-treehouse/src/iosMain/kotlin/app/cash/redwood/treehouse/TreehouseSwiftUIView.kt +++ b/redwood-treehouse/src/iosMain/kotlin/app/cash/redwood/treehouse/TreehouseSwiftUIView.kt @@ -22,7 +22,7 @@ import app.cash.redwood.widget.Widget import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -public class TreehouseSwiftUIView( +public class TreehouseSwiftUIView( private val treehouseApp: TreehouseApp, override val widgetSystem: TreehouseView.WidgetSystem, ) : TreehouseView, SwiftUIView { diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp.xcodeproj/project.pbxproj b/samples/emoji-search/ios/swiftUI/EmojiSearchApp.xcodeproj/project.pbxproj index 5be32f348d..22f3c3cdf8 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp.xcodeproj/project.pbxproj +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 56; + objectVersion = 50; objects = { /* Begin PBXBuildFile section */ diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/TreehouseUIRenderer.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/TreehouseUIRenderer.swift index 59de3e7b11..cc823e323c 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/TreehouseUIRenderer.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/TreehouseUIRenderer.swift @@ -32,7 +32,7 @@ private class ContentWrapper: Redwood_treehouseTreehouseViewContent { self.treehouseUI = treehouseUI } - func get(app: Any) -> Redwood_treehouseZiplineTreehouseUi { + func get(app: Redwood_treehouseAppService) -> Redwood_treehouseZiplineTreehouseUi { return treehouseUI } diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/EmojiSearchApp.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/EmojiSearchApp.swift index 641988c960..cae7a7a866 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/EmojiSearchApp.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/EmojiSearchApp.swift @@ -19,20 +19,20 @@ struct EmojiSearchApp: App { } class EmojiSearchContent : Redwood_treehouseTreehouseViewContent { - func get(app: Any) -> Redwood_treehouseZiplineTreehouseUi { + func get(app: Redwood_treehouseAppService) -> Redwood_treehouseZiplineTreehouseUi { let treehouesUi = (app as! PresentersEmojiSearchPresenter) return treehouesUi.launch() } } - class EmojiSearchWidgetSystem : Redwood_treehouseTreehouseViewWidgetSystem { - func widgetFactory(app: Redwood_treehouseTreehouseApp, + + func widgetFactory(app: Redwood_treehouseTreehouseApp, json: Kotlinx_serialization_jsonJson, protocolMismatchHandler: Redwood_protocol_widgetProtocolMismatchHandler ) -> Redwood_protocol_widgetDiffConsumingNodeFactory { - return ExposedKt.diffConsumingEmojiSearchWidgetFactory( - delegate: SwiftUIEmojiSearchWidgetFactory(treehouseApp: app, widgetSystem: self), + return ProtocolEmojiSearchDiffConsumingNodeFactory( + widgets: SwiftUIEmojiSearchWidgetFactory(treehouseApp: app, widgetSystem: self), json: json, mismatchHandler: protocolMismatchHandler ); From e1359c4eaea63618a961fba4326524cf07e37436 Mon Sep 17 00:00:00 2001 From: Alex Skorulis Date: Tue, 13 Dec 2022 13:31:48 +1100 Subject: [PATCH 10/13] Code cleanup --- .../app/cash/zipline/samples/emojisearch/exposed.kt | 4 +--- .../swiftUI/EmojiSearchApp/Core/EnvironmentKeys.swift | 9 ++++----- .../EmojiSearchApp/Core/TreehouseUIRenderer.swift | 2 +- .../ios/swiftUI/EmojiSearchApp/Scene/ContentView.swift | 4 ++-- .../swiftUI/EmojiSearchApp/Scene/ContentViewModel.swift | 4 ++++ .../EmojiSearchApp/Widget/LazyColumnBinding.swift | 3 --- 6 files changed, 12 insertions(+), 14 deletions(-) diff --git a/samples/emoji-search/ios/shared/src/commonMain/kotlin/app/cash/zipline/samples/emojisearch/exposed.kt b/samples/emoji-search/ios/shared/src/commonMain/kotlin/app/cash/zipline/samples/emojisearch/exposed.kt index 30d793e404..ceb8908b01 100644 --- a/samples/emoji-search/ios/shared/src/commonMain/kotlin/app/cash/zipline/samples/emojisearch/exposed.kt +++ b/samples/emoji-search/ios/shared/src/commonMain/kotlin/app/cash/zipline/samples/emojisearch/exposed.kt @@ -47,9 +47,7 @@ fun exposedTypes( treehouseSwiftUIView: TreehouseSwiftUIView<*>, layoutWidgetFactory: RedwoodLayoutWidgetFactory<*>, swiftUIView: SwiftUIView, - swiftUIChildren: SwiftUIChildren, - stateFlow: StateFlow<*>, - hostConfiguration: HostConfiguration + swiftUIChildren: SwiftUIChildren ) { throw AssertionError() } diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/EnvironmentKeys.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/EnvironmentKeys.swift index cce78fd7f9..a1bf9701cc 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/EnvironmentKeys.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/EnvironmentKeys.swift @@ -5,13 +5,12 @@ import shared import SwiftUI public struct TreehouseAppKey: EnvironmentKey { - // TODO: This type shouldn't be bound to PresentersEmojiSearchPresenter - public static var defaultValue: (Redwood_treehouseTreehouseApp)? = nil + public static var defaultValue: (Redwood_treehouseTreehouseApp)? = nil } public extension EnvironmentValues { - var treehouseApp: (Redwood_treehouseTreehouseApp)? { + var treehouseApp: (Redwood_treehouseTreehouseApp)? { get { self[TreehouseAppKey.self] } set { self[TreehouseAppKey.self] = newValue } } @@ -19,12 +18,12 @@ public extension EnvironmentValues { struct WidgetSystemKey: EnvironmentKey { - static var defaultValue: (EmojiSearchWidgetSystem)? = nil + static var defaultValue: (Redwood_treehouseTreehouseViewWidgetSystem)? = nil } extension EnvironmentValues { - var treehouseWidgetSystem: (EmojiSearchWidgetSystem)? { + var treehouseWidgetSystem: (Redwood_treehouseTreehouseViewWidgetSystem)? { get { self[WidgetSystemKey.self] } set { self[WidgetSystemKey.self] = newValue } } diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/TreehouseUIRenderer.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/TreehouseUIRenderer.swift index cc823e323c..8481c3e167 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/TreehouseUIRenderer.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/TreehouseUIRenderer.swift @@ -6,7 +6,7 @@ import SwiftUI struct TreehouseUIRenderer: View { - let treehouseUI: any Redwood_treehouseZiplineTreehouseUi + let treehouseUI: Redwood_treehouseZiplineTreehouseUi @Environment(\.treehouseApp) private var treehouseApp @Environment(\.treehouseWidgetSystem) private var treehouseWidgetSystem diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/ContentView.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/ContentView.swift index 8faa146f59..8540fa1963 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/ContentView.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/ContentView.swift @@ -8,8 +8,8 @@ struct ContentView: View { var body: some View { TreehouseViewRenderer(treehouseView: viewModel.treehouseView) - .environment(\.treehouseApp, viewModel.treehouseApp) - .environment(\.treehouseWidgetSystem, viewModel.widgetSystem) + .environment(\.treehouseApp, viewModel.anyApp) + .environment(\.treehouseWidgetSystem, viewModel.widgetSystem) } } diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/ContentViewModel.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/ContentViewModel.swift index 060cc1d8f0..a2e15a4313 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/ContentViewModel.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/ContentViewModel.swift @@ -10,6 +10,10 @@ final class ContentViewModel: ObservableObject { let treehouseApp: Redwood_treehouseTreehouseApp let widgetSystem: EmojiSearchWidgetSystem + + var anyApp: Redwood_treehouseTreehouseApp { + treehouseApp as! Redwood_treehouseTreehouseApp + } init() { let emojiSearchLauncher = EmojiSearchLauncher(nsurlSession: urlSession, hostApi: IosHostApi()) diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/LazyColumnBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/LazyColumnBinding.swift index 15fc8ec11e..8f7645967e 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/LazyColumnBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/LazyColumnBinding.swift @@ -21,9 +21,6 @@ struct LazyColumnView: View { @ObservedObject var binding: LazyColumnBinding - @Environment(\.treehouseApp) private var treehouseApp - @Environment(\.treehouseWidgetSystem) private var treehouseWidgetSystem - var body: some View { LazyVStack { ForEach(Array(binding.intervals.indices), id: \.self) { index in From 5904d267d353f6a39c1cb556b8f56ddca9caa894 Mon Sep 17 00:00:00 2001 From: Alex Skorulis Date: Tue, 13 Dec 2022 13:39:54 +1100 Subject: [PATCH 11/13] Update copyright --- .../EmojiSearchApp/Core/EnvironmentKeys.swift | 16 ++++++- .../Core/SwiftUIViewBinding.swift | 16 ++++++- .../Core/TreehouseUIRenderer.swift | 16 ++++++- .../Core/TreehouseViewRenderer.swift | 16 ++++++- .../Core/WidgetChildrenObserver.swift | 16 ++++++- .../Core/WidgetChildrenView.swift | 16 ++++++- .../EmojiSearchApp/Scene/ContentView.swift | 16 ++++++- .../Scene/ContentViewModel.swift | 38 ++++++++++++++++- .../EmojiSearchApp/Scene/EmojiSearchApp.swift | 42 +++++++------------ .../EmojiSearchApp/Widget/BaseWidget.swift | 16 ++++++- .../EmojiSearchApp/Widget/ColumnBinding.swift | 16 ++++++- .../EmojiSearchApp/Widget/ImageBinding.swift | 16 ++++++- .../Widget/LazyColumnBinding.swift | 16 ++++++- .../EmojiSearchApp/Widget/RowBinding.swift | 16 ++++++- .../Widget/TextInputBinding.swift | 16 ++++++- .../SwiftUIEmojiSearchWidgetFactory.swift | 16 ++++++- .../SwiftUILayoutWidgetFactory.swift | 16 ++++++- .../SwiftUILazyLayoutWidgetFactory.swift | 16 ++++++- 18 files changed, 292 insertions(+), 44 deletions(-) diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/EnvironmentKeys.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/EnvironmentKeys.swift index a1bf9701cc..2aa4a80193 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/EnvironmentKeys.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/EnvironmentKeys.swift @@ -1,4 +1,18 @@ -// Copyright © Square, Inc. All rights reserved. +/* + * Copyright (C) 2022 Square, Inc. + * + * 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 Foundation import shared diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/SwiftUIViewBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/SwiftUIViewBinding.swift index 842e8574a4..3a29ef9cda 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/SwiftUIViewBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/SwiftUIViewBinding.swift @@ -1,4 +1,18 @@ -// Copyright © Square, Inc. All rights reserved. +/* + * Copyright (C) 2022 Square, Inc. + * + * 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 Foundation import shared diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/TreehouseUIRenderer.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/TreehouseUIRenderer.swift index 8481c3e167..056e3876ff 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/TreehouseUIRenderer.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/TreehouseUIRenderer.swift @@ -1,4 +1,18 @@ -// Copyright © Square, Inc. All rights reserved. +/* + * Copyright (C) 2022 Square, Inc. + * + * 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 Foundation import shared diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/TreehouseViewRenderer.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/TreehouseViewRenderer.swift index a9d33443ad..0511ec0515 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/TreehouseViewRenderer.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/TreehouseViewRenderer.swift @@ -1,4 +1,18 @@ -// Copyright © Square, Inc. All rights reserved. +/* + * Copyright (C) 2022 Square, Inc. + * + * 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 Foundation import shared diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenObserver.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenObserver.swift index b166d5bb76..db449c4460 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenObserver.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenObserver.swift @@ -1,4 +1,18 @@ -// Copyright © Square, Inc. All rights reserved. +/* + * Copyright (C) 2022 Square, Inc. + * + * 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 Foundation import shared diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenView.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenView.swift index a6372e9da4..63df940e7f 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenView.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Core/WidgetChildrenView.swift @@ -1,4 +1,18 @@ -// Copyright © Square, Inc. All rights reserved. +/* + * Copyright (C) 2022 Square, Inc. + * + * 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 Foundation import SwiftUI diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/ContentView.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/ContentView.swift index 8540fa1963..eeeb425291 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/ContentView.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/ContentView.swift @@ -1,4 +1,18 @@ -// Copyright © Square, Inc. All rights reserved. +/* + * Copyright (C) 2022 Square, Inc. + * + * 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 SwiftUI diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/ContentViewModel.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/ContentViewModel.swift index a2e15a4313..059feb5d05 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/ContentViewModel.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/ContentViewModel.swift @@ -1,4 +1,18 @@ -// Copyright © Square, Inc. All rights reserved. +/* + * Copyright (C) 2022 Square, Inc. + * + * 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 Foundation import shared @@ -29,3 +43,25 @@ final class ContentViewModel: ObservableObject { } } + +class EmojiSearchContent : Redwood_treehouseTreehouseViewContent { + func get(app: Redwood_treehouseAppService) -> Redwood_treehouseZiplineTreehouseUi { + let treehouesUi = (app as! PresentersEmojiSearchPresenter) + return treehouesUi.launch() + } +} + +class EmojiSearchWidgetSystem : Redwood_treehouseTreehouseViewWidgetSystem { + + func widgetFactory(app: Redwood_treehouseTreehouseApp, + json: Kotlinx_serialization_jsonJson, + protocolMismatchHandler: Redwood_protocol_widgetProtocolMismatchHandler + ) -> Redwood_protocol_widgetDiffConsumingNodeFactory { + return ProtocolEmojiSearchDiffConsumingNodeFactory( + widgets: SwiftUIEmojiSearchWidgetFactory(treehouseApp: app, widgetSystem: self), + json: json, + mismatchHandler: protocolMismatchHandler + ); + } +} + diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/EmojiSearchApp.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/EmojiSearchApp.swift index cae7a7a866..51db35f5c5 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/EmojiSearchApp.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Scene/EmojiSearchApp.swift @@ -1,4 +1,18 @@ -// Copyright © Square, Inc. All rights reserved. +/* + * Copyright (C) 2022 Square, Inc. + * + * 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 SwiftUI import shared @@ -6,10 +20,6 @@ import shared @main struct EmojiSearchApp: App { - init() { - - } - var body: some Scene { WindowGroup { ContentView(viewModel: ContentViewModel()) @@ -17,25 +27,3 @@ struct EmojiSearchApp: App { } } - -class EmojiSearchContent : Redwood_treehouseTreehouseViewContent { - func get(app: Redwood_treehouseAppService) -> Redwood_treehouseZiplineTreehouseUi { - let treehouesUi = (app as! PresentersEmojiSearchPresenter) - return treehouesUi.launch() - } -} - -class EmojiSearchWidgetSystem : Redwood_treehouseTreehouseViewWidgetSystem { - - func widgetFactory(app: Redwood_treehouseTreehouseApp, - json: Kotlinx_serialization_jsonJson, - protocolMismatchHandler: Redwood_protocol_widgetProtocolMismatchHandler - ) -> Redwood_protocol_widgetDiffConsumingNodeFactory { - return ProtocolEmojiSearchDiffConsumingNodeFactory( - widgets: SwiftUIEmojiSearchWidgetFactory(treehouseApp: app, widgetSystem: self), - json: json, - mismatchHandler: protocolMismatchHandler - ); - } -} - diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/BaseWidget.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/BaseWidget.swift index 9ccc413e20..d526d1b376 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/BaseWidget.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/BaseWidget.swift @@ -1,4 +1,18 @@ -// Copyright © Square, Inc. All rights reserved. +/* + * Copyright (C) 2022 Square, Inc. + * + * 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 Foundation import shared diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift index df3d5badba..40d9ddd331 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift @@ -1,4 +1,18 @@ -// Copyright © Square, Inc. All rights reserved. +/* + * Copyright (C) 2022 Square, Inc. + * + * 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 Foundation import shared diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ImageBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ImageBinding.swift index c238550b13..ba4ba66e8b 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ImageBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ImageBinding.swift @@ -1,4 +1,18 @@ -// Copyright © Square, Inc. All rights reserved. +/* + * Copyright (C) 2022 Square, Inc. + * + * 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 Foundation import shared diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/LazyColumnBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/LazyColumnBinding.swift index 8f7645967e..cdedbf7728 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/LazyColumnBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/LazyColumnBinding.swift @@ -1,4 +1,18 @@ -// Copyright © Square, Inc. All rights reserved. +/* + * Copyright (C) 2022 Square, Inc. + * + * 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 Foundation import shared diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/RowBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/RowBinding.swift index 83c19e2cc8..01095f1966 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/RowBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/RowBinding.swift @@ -1,4 +1,18 @@ -// Copyright © Square, Inc. All rights reserved. +/* + * Copyright (C) 2022 Square, Inc. + * + * 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 Foundation import shared diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextInputBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextInputBinding.swift index a632be9873..f93de07752 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextInputBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextInputBinding.swift @@ -1,4 +1,18 @@ -// Copyright © Square, Inc. All rights reserved. +/* + * Copyright (C) 2022 Square, Inc. + * + * 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 Foundation import shared diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUIEmojiSearchWidgetFactory.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUIEmojiSearchWidgetFactory.swift index 88d109db3d..7af34333e7 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUIEmojiSearchWidgetFactory.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUIEmojiSearchWidgetFactory.swift @@ -1,4 +1,18 @@ -// Copyright © Square, Inc. All rights reserved. +/* + * Copyright (C) 2022 Square, Inc. + * + * 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 Foundation import shared diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUILayoutWidgetFactory.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUILayoutWidgetFactory.swift index 9c430398f1..ef3d55bb15 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUILayoutWidgetFactory.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUILayoutWidgetFactory.swift @@ -1,4 +1,18 @@ -// Copyright © Square, Inc. All rights reserved. +/* + * Copyright (C) 2022 Square, Inc. + * + * 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 Foundation import shared diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUILazyLayoutWidgetFactory.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUILazyLayoutWidgetFactory.swift index 8b7bfca7d2..8fddedfdf0 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUILazyLayoutWidgetFactory.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/WidgetFactory/SwiftUILazyLayoutWidgetFactory.swift @@ -1,4 +1,18 @@ -// Copyright © Square, Inc. All rights reserved. +/* + * Copyright (C) 2022 Square, Inc. + * + * 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 Foundation import shared From d10c86a160c652349c2ede05432df9c95b749031 Mon Sep 17 00:00:00 2001 From: Alex Skorulis Date: Tue, 13 Dec 2022 13:50:25 +1100 Subject: [PATCH 12/13] Add extra dependency --- samples/emoji-search/ios/shared/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/emoji-search/ios/shared/build.gradle b/samples/emoji-search/ios/shared/build.gradle index 9488ad305f..58f9bc2aec 100644 --- a/samples/emoji-search/ios/shared/build.gradle +++ b/samples/emoji-search/ios/shared/build.gradle @@ -13,6 +13,7 @@ kotlin { sourceSets { commonMain { dependencies { + api projects.redwoodLayoutSchema.widget implementation projects.samples.emojiSearch.launcher implementation projects.samples.emojiSearch.presenters implementation projects.samples.emojiSearch.schema.widget.protocol From e588c935545d2b66ba6a29570ffcee4fbd0f3898 Mon Sep 17 00:00:00 2001 From: Alex Skorulis Date: Tue, 13 Dec 2022 14:02:39 +1100 Subject: [PATCH 13/13] Code cleanup --- .../app/cash/zipline/samples/emojisearch/exposed.kt | 12 +++++------- .../EmojiSearchApp/Widget/ColumnBinding.swift | 1 - .../EmojiSearchApp/Widget/LazyColumnBinding.swift | 1 - .../EmojiSearchApp/Widget/TextInputBinding.swift | 1 - 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/samples/emoji-search/ios/shared/src/commonMain/kotlin/app/cash/zipline/samples/emojisearch/exposed.kt b/samples/emoji-search/ios/shared/src/commonMain/kotlin/app/cash/zipline/samples/emojisearch/exposed.kt index ceb8908b01..da10f83b5f 100644 --- a/samples/emoji-search/ios/shared/src/commonMain/kotlin/app/cash/zipline/samples/emojisearch/exposed.kt +++ b/samples/emoji-search/ios/shared/src/commonMain/kotlin/app/cash/zipline/samples/emojisearch/exposed.kt @@ -19,20 +19,18 @@ package app.cash.zipline.samples.emojisearch import app.cash.redwood.LayoutModifier import app.cash.redwood.layout.uiview.UIViewRedwoodLayoutWidgetFactory +import app.cash.redwood.layout.widget.RedwoodLayoutWidgetFactory +import app.cash.redwood.treehouse.TreehouseSwiftUIView import app.cash.redwood.treehouse.TreehouseUIKitView import app.cash.redwood.treehouse.TreehouseView -import app.cash.redwood.treehouse.TreehouseSwiftUIView -import app.cash.redwood.widget.SwiftUIView -import app.cash.redwood.widget.SwiftUIChildren import app.cash.redwood.treehouse.lazylayout.uiview.UIViewRedwoodTreehouseLazyLayoutWidgetFactory +import app.cash.redwood.widget.SwiftUIChildren +import app.cash.redwood.widget.SwiftUIView import example.schema.widget.EmojiSearchDiffConsumingNodeFactory import example.schema.widget.EmojiSearchWidgetFactory import okio.ByteString import okio.toByteString import platform.Foundation.NSData -import app.cash.redwood.layout.widget.RedwoodLayoutWidgetFactory -import kotlinx.coroutines.flow.StateFlow -import app.cash.redwood.treehouse.HostConfiguration // Used to export types to Objective-C / Swift. fun exposedTypes( @@ -47,7 +45,7 @@ fun exposedTypes( treehouseSwiftUIView: TreehouseSwiftUIView<*>, layoutWidgetFactory: RedwoodLayoutWidgetFactory<*>, swiftUIView: SwiftUIView, - swiftUIChildren: SwiftUIChildren + swiftUIChildren: SwiftUIChildren, ) { throw AssertionError() } diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift index 40d9ddd331..e8712fd63c 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/ColumnBinding.swift @@ -49,7 +49,6 @@ final class ColumnBinding: BaseWidget, WidgetColumn, SwiftUIViewBinding { } - struct ColumnView: View { @ObservedObject var binding: ColumnBinding diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/LazyColumnBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/LazyColumnBinding.swift index cdedbf7728..28c828667c 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/LazyColumnBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/LazyColumnBinding.swift @@ -47,7 +47,6 @@ struct LazyColumnView: View { } .id(binding.randomID) } - } struct LazyCell: View { diff --git a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextInputBinding.swift b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextInputBinding.swift index f93de07752..5df2748f72 100644 --- a/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextInputBinding.swift +++ b/samples/emoji-search/ios/swiftUI/EmojiSearchApp/Widget/TextInputBinding.swift @@ -62,7 +62,6 @@ final class TextInputBinding: BaseWidget, WidgetTextInput, SwiftUIViewBinding { } } } - } struct TextInputView: View {