Skip to content

Commit

Permalink
Add simple navigation to test app (#1487)
Browse files Browse the repository at this point in the history
* Add simple navigation to test app

For some reason iOS is broken and never receives the click within the JS. Will look into separately.

* Update test-app/presenter/src/commonMain/kotlin/com/example/redwood/testing/presenter/TestApp.kt

Co-authored-by: Veyndan Stuart <[email protected]>

---------

Co-authored-by: Veyndan Stuart <[email protected]>
  • Loading branch information
JakeWharton and veyndan authored Sep 15, 2023
1 parent c03cf30 commit a287adc
Show file tree
Hide file tree
Showing 10 changed files with 193 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ package com.example.redwood.testing.android.views

import android.content.Context
import android.view.View
import android.widget.Button as ButtonWidget
import android.widget.TextView
import com.example.redwood.testing.widget.Button
import com.example.redwood.testing.widget.TestSchemaWidgetFactory
import com.example.redwood.testing.widget.Text

Expand All @@ -27,7 +29,7 @@ class AndroidTestSchemaWidgetFactory(
override fun Text(): Text<View> = ViewText(TextView(context))
override fun TestRow() = throw UnsupportedOperationException()
override fun ScopedTestRow() = throw UnsupportedOperationException()
override fun Button() = TODO()
override fun Button(): Button<View> = ViewButton(ButtonWidget(context))
override fun Button2() = TODO()
override fun TextInput() = TODO()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2023 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 com.example.redwood.testing.android.views

import android.view.View
import android.widget.Button as WidgetButton
import app.cash.redwood.Modifier
import com.example.redwood.testing.widget.Button

internal class ViewButton(
override val value: WidgetButton,
) : Button<View> {
override var modifier: Modifier = Modifier

override fun text(text: String?) {
value.text = text
}

override fun onClick(onClick: (() -> Unit)?) {
value.setOnClickListener(
if (onClick != null) {
{ onClick.invoke() }
} else {
null
},
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import app.cash.redwood.layout.dom.HTMLElementRedwoodLayoutWidgetFactory
import app.cash.redwood.lazylayout.dom.HTMLElementRedwoodLazyLayoutWidgetFactory
import app.cash.redwood.widget.asRedwoodView
import com.example.redwood.testing.presenter.HttpClient
import com.example.redwood.testing.presenter.RepoSearch
import com.example.redwood.testing.presenter.TestApp
import com.example.redwood.testing.widget.TestSchemaWidgetFactories
import kotlin.js.json
import kotlinx.browser.document
Expand Down Expand Up @@ -54,6 +54,6 @@ fun main() {
}

composition.setContent {
RepoSearch(client)
TestApp(client)
}
}
4 changes: 4 additions & 0 deletions test-app/ios-uikit/TestApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
635661DC21F12B8000DD7240 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 635661DB21F12B8000DD7240 /* Assets.xcassets */; };
635661DF21F12B8000DD7240 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 635661DD21F12B8000DD7240 /* LaunchScreen.storyboard */; };
CB85C0B725AFE61A007A2CC7 /* TestAppViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB85C0B625AFE61A007A2CC7 /* TestAppViewController.swift */; };
CB9E3E822AB379C4007A87CD /* ButtonBinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB9E3E812AB379C4007A87CD /* ButtonBinding.swift */; };
CB9F76562810A8A8008CF457 /* IosHostApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB9F76552810A8A8008CF457 /* IosHostApi.swift */; };
/* End PBXBuildFile section */

Expand All @@ -28,6 +29,7 @@
635661E021F12B8000DD7240 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
63E90CF521FEBBB700449E04 /* main.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = main.framework; path = "../ios-shared/build/xcode-frameworks/main.framework"; sourceTree = "<group>"; };
CB85C0B625AFE61A007A2CC7 /* TestAppViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestAppViewController.swift; sourceTree = "<group>"; };
CB9E3E812AB379C4007A87CD /* ButtonBinding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonBinding.swift; sourceTree = "<group>"; };
CB9F76552810A8A8008CF457 /* IosHostApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IosHostApi.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -71,6 +73,7 @@
CB9F76552810A8A8008CF457 /* IosHostApi.swift */,
10AA3D4B28C03D32006F125E /* IosTestSchemaWidgetFactory.swift */,
10AA3D4D28C0EA40006F125E /* TextBinding.swift */,
CB9E3E812AB379C4007A87CD /* ButtonBinding.swift */,
);
path = TestApp;
sourceTree = "<group>";
Expand Down Expand Up @@ -169,6 +172,7 @@
buildActionMask = 2147483647;
files = (
10AA3D4C28C03D32006F125E /* IosTestSchemaWidgetFactory.swift in Sources */,
CB9E3E822AB379C4007A87CD /* ButtonBinding.swift in Sources */,
CB85C0B725AFE61A007A2CC7 /* TestAppViewController.swift in Sources */,
10AA3D4E28C0EA40006F125E /* TextBinding.swift in Sources */,
635661D521F12B7E00DD7240 /* AppDelegate.swift in Sources */,
Expand Down
54 changes: 54 additions & 0 deletions test-app/ios-uikit/TestApp/ButtonBinding.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright (C) 2023 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 TestAppKt
import UIKit

class ButtonBinding: Button {
private let root: UIButton = {
let view = UIButton()
view.backgroundColor = UIColor.gray
return view
}()

var modifier: Modifier = ExposedKt.modifier()
var value: Any { root }
var onClick: (() -> Void)? = nil

func text(text: String?) {
root.setTitle(text, for: .normal)

// This very simple integration wraps the size of whatever text is entered. Calling
// this function will update the bounds and trigger relayout in the parent.
root.sizeToFit()
}

func onClick(onClick: (() -> Void)? = nil) {
self.onClick = onClick
if (onClick != nil) {
root.addTarget(self, action: #selector(clicked), for: .touchUpInside)
} else {
root.removeTarget(self, action: #selector(clicked), for: .touchUpInside)
}
}

@objc func clicked() {
if (self.onClick != nil) {
self.onClick()
}
}
}
12 changes: 2 additions & 10 deletions test-app/ios-uikit/TestApp/IosTestSchemaWidgetFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,7 @@ import Foundation
import UIKit
import TestAppKt

class IosTestSchemaWidgetFactory<A : AnyObject>: TestSchemaWidgetFactory {
let treehouseApp: TreehouseApp<A>
let widgetSystem: TreehouseViewWidgetSystem

init(treehouseApp: TreehouseApp<A>, widgetSystem: TreehouseViewWidgetSystem) {
self.treehouseApp = treehouseApp
self.widgetSystem = widgetSystem
}

class IosTestSchemaWidgetFactory: TestSchemaWidgetFactory {
func TextInput() -> TextInput {
fatalError()
}
Expand All @@ -37,7 +29,7 @@ class IosTestSchemaWidgetFactory<A : AnyObject>: TestSchemaWidgetFactory {
}

func Button() -> Button {
fatalError()
return ButtonBinding()
}

func Button2() -> Button2 {
Expand Down
10 changes: 2 additions & 8 deletions test-app/ios-uikit/TestApp/TestAppViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class TestAppViewController : UIViewController {
override func loadView() {
let testAppLauncher = TestAppLauncher(nsurlSession: urlSession, hostApi: IosHostApi())
let treehouseApp = testAppLauncher.createTreehouseApp()
let widgetSystem = TestSchemaWidgetSystem(treehouseApp: treehouseApp)
let widgetSystem = TestSchemaWidgetSystem()
let treehouseView = TreehouseUIView(widgetSystem: widgetSystem)
let content = treehouseApp.createContent(
source: TestAppContent(),
Expand All @@ -54,19 +54,13 @@ class TestAppContent : TreehouseContentSource {
}

class TestSchemaWidgetSystem : TreehouseViewWidgetSystem {
let treehouseApp: TreehouseApp<TestAppPresenter>

init(treehouseApp: TreehouseApp<TestAppPresenter>) {
self.treehouseApp = treehouseApp
}

func widgetFactory(
json: Kotlinx_serialization_jsonJson,
protocolMismatchHandler: ProtocolMismatchHandler
) -> ProtocolNodeFactory {
return TestSchemaProtocolNodeFactory<UIView>(
provider: TestSchemaWidgetFactories<UIView>(
TestSchema: IosTestSchemaWidgetFactory(treehouseApp: treehouseApp, widgetSystem: self),
TestSchema: IosTestSchemaWidgetFactory(),
RedwoodLayout: UIViewRedwoodLayoutWidgetFactory(),
RedwoodLazyLayout: UIViewRedwoodLazyLayoutWidgetFactory()
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ package com.example.redwood.testing.treehouse
import androidx.compose.runtime.Composable
import app.cash.redwood.treehouse.TreehouseUi
import com.example.redwood.testing.presenter.HttpClient
import com.example.redwood.testing.presenter.RepoSearch
import com.example.redwood.testing.presenter.TestApp

class TestAppTreehouseUi(
private val httpClient: HttpClient,
) : TreehouseUi {
@Composable
override fun Show() {
RepoSearch(httpClient)
TestApp(httpClient)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import app.cash.paging.PagingSourceLoadResult
import app.cash.paging.PagingSourceLoadResultPage
import app.cash.paging.PagingState
import app.cash.paging.compose.collectAsLazyPagingItems
import app.cash.redwood.Modifier
import app.cash.redwood.layout.api.Constraint
import app.cash.redwood.lazylayout.compose.LazyColumn
import kotlinx.serialization.json.Json
Expand All @@ -38,7 +39,7 @@ private val pagingConfig = PagingConfig(pageSize = 20, initialLoadSize = 20).app
}

@Composable
fun RepoSearch(httpClient: HttpClient) {
internal fun RepoSearch(httpClient: HttpClient, modifier: Modifier = Modifier) {
// TODO Make term interactive with TextInput.
val latestSearchTerm by remember { mutableStateOf("android") }

Expand All @@ -51,6 +52,8 @@ fun RepoSearch(httpClient: HttpClient) {
val lazyPagingItems = pager.flow.collectAsLazyPagingItems()
LazyColumn(
width = Constraint.Fill,
height = Constraint.Fill,
modifier = modifier,
placeholder = { RepositoryItem(Repository(fullName = "Placeholder…", 0)) },
) {
items(lazyPagingItems.itemCount) { index ->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (C) 2023 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 com.example.redwood.testing.presenter

import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import app.cash.redwood.Modifier
import app.cash.redwood.layout.api.Constraint
import app.cash.redwood.layout.api.Constraint.Companion
import app.cash.redwood.layout.api.CrossAxisAlignment
import app.cash.redwood.layout.api.Overflow
import app.cash.redwood.layout.compose.Column
import app.cash.redwood.ui.Margin
import app.cash.redwood.ui.dp
import com.example.redwood.testing.compose.Button
import com.example.redwood.testing.compose.Text

@Composable
fun TestApp(httpClient: HttpClient) {
val screen = remember { mutableStateOf<Screen?>(null) }
val activeScreen = screen.value
if (activeScreen == null) {
HomeScreen(screen)
} else {
Column(
width = Constraint.Fill,
height = Constraint.Fill,
) {
Button("Back", onClick = { screen.value = null })
activeScreen.Show(httpClient, modifier = Modifier.grow(1.0))
}
}
}

@Suppress("unused") // Used via reflection.
enum class Screen {
RepoSearch {
@Composable
override fun Show(httpClient: HttpClient, modifier: Modifier) {
RepoSearch(httpClient, modifier)
}
},
;

@Composable
abstract fun Show(httpClient: HttpClient, modifier: Modifier)
}

@Composable
private fun HomeScreen(screen: MutableState<Screen?>) {
Column(
width = Constraint.Fill,
height = Companion.Fill,
overflow = Overflow.Scroll,
horizontalAlignment = CrossAxisAlignment.Stretch,
) {
Text("Test App Screens:", modifier = Modifier.margin(Margin(8.dp)))
Screen.entries.forEach {
Button(it.name, onClick = {
screen.value = it
})
}
}
}

0 comments on commit a287adc

Please sign in to comment.