Skip to content

Commit

Permalink
🌱 StateTree v0.1.0
Browse files Browse the repository at this point in the history
This commit marks the end of initial feature-set development.
StateTree does what it's meant to.

Changes since v0.0.99 include:
- @route reimplementation to allow non-optional routes and
  a much more natural syntax.
- Behavior reimplementation to ensure deterministic interception
  and registration before start.
- URL encoded Intent payloads for simple deeplinking.
- State application/playback reimplementation for stability.
- Third Party dependency removals.
- Tree lifecycle API changes to remove implementation details
  from the API. (i.e. The Disposable and Emitter libraries.)
- Test hooks for update counts to allow performance/behavior
  assertions.
- UI-layer module API improvements for ease of use.
- Significant changes to lifecycle Rules to integrate Behaviors
  as their actions, and so to allow runtime implementation
  swapping.
- Linux testing and stabilization.
- Custom @treeactor testing and stabilization.
- Xcode 15 / Swift 5.9 fixes.
- Example app migrations.

And more.

🌅

-adamz
  • Loading branch information
adam-zethraeus committed Jun 8, 2023
1 parent c88a09f commit 9a56e84
Show file tree
Hide file tree
Showing 399 changed files with 22,418 additions and 10,768 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.vscode
.DS_Store
/.build
/Packages
Expand All @@ -8,3 +9,4 @@ DerivedData/
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
.swiftpm
docs/
2 changes: 1 addition & 1 deletion .swift-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
5.7
5.9
2 changes: 0 additions & 2 deletions .swiftformat
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
--rules numberFormatting
--rules opaqueGenericParameters
--rules organizeDeclarations
--rules preferDouble
--rules preferKeyPath
--rules redundantBackticks
--rules redundantBreak
Expand All @@ -41,7 +40,6 @@
--rules redundantParens
--rules redundantPattern
--rules redundantRawValues
--rules redundantReturn
--rules redundantSelf
--rules redundantType
--rules redundantVoidReturnType
Expand Down

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/GoodHatsLLC/Disposable.git",
"state" : {
"revision" : "7529c939ffa7e2d3f635d709ff7b14307173916f",
"version" : "0.4.0"
"revision" : "2b6db4e812dc2dddb7743251224c29308976b3e3",
"version" : "0.8.0"
}
},
{
"identity" : "emitter",
"kind" : "remoteSourceControl",
"location" : "https://github.com/GoodHatsLLC/Emitter.git",
"state" : {
"revision" : "2736f37612a8cb86a65eaf4a59f98e0df242c63c",
"version" : "0.1.4"
"revision" : "84614b2f05e51deb1ada3bd9fc36bf431bc25e44",
"version" : "0.8.5"
}
},
{
Expand All @@ -24,7 +24,7 @@
"location" : "https://github.com/apple/swift-collections.git",
"state" : {
"branch" : "release/1.1",
"revision" : "8c7b8536ea0d21faeeb05229aa7537e9e2636794"
"revision" : "992e0f3446b4f608f5ead9dd6edc92f6bbc0b0a0"
}
}
],
Expand Down
30 changes: 30 additions & 0 deletions Examples/Counter/Counter/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import UIKit

/// Standard UIKit boilerplate.
@main
class AppDelegate: UIResponder, UIApplicationDelegate {

func application(
_: UIApplication,
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?
)
-> Bool
{
true
}

// MARK: UISceneSession Lifecycle

func application(
_: UIApplication,
configurationForConnecting connectingSceneSession: UISceneSession,
options _: UIScene.ConnectionOptions
)
-> UISceneConfiguration
{
UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}

func application(_: UIApplication, didDiscardSceneSessions _: Set<UISceneSession>) { }

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{
"colors" : [
{
"color" : {
"platform" : "universal",
"reference" : "systemPinkColor"
},
"idiom" : "universal"
}
],
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"images" : [
{
"filename" : "AppIcon.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
25 changes: 25 additions & 0 deletions Examples/Counter/Counter/Base.lproj/LaunchScreen.storyboard
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>
23 changes: 23 additions & 0 deletions Examples/Counter/Counter/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
</dict>
</array>
</dict>
</dict>
</dict>
</plist>
44 changes: 44 additions & 0 deletions Examples/Counter/Counter/SceneDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import CounterDomain
import CounterUI
import StateTree
import StateTreeImperativeUI
import UIKit

/// We use the SceneDelegate as our entry point into our StateTree
/// defined domain logic.
/// (The rest of the Counter example code is in the `CounterSupport` package.)
final class SceneDelegate: UIResponder, UIWindowSceneDelegate {

var window: UIWindow?

/// The model representing our StateTree
///
/// This Tree manages all of our models
let tree = try! ReportedTree(tree: Tree(root: CountersList()))

func scene(
_ scene: UIScene, willConnectTo _: UISceneSession, options _: UIScene.ConnectionOptions
) {
guard let scene = (scene as? UIWindowScene) else {
return
}
let mainWindow = UIWindow(windowScene: scene)
window = mainWindow

let root = tree.root
mainWindow.rootViewController = RootViewController(model: root)

window?.makeKeyAndVisible()
}

func sceneDidDisconnect(_: UIScene) { }

func sceneDidBecomeActive(_: UIScene) { }

func sceneWillResignActive(_: UIScene) { }

func sceneWillEnterForeground(_: UIScene) { }

func sceneDidEnterBackground(_: UIScene) { }

}
42 changes: 42 additions & 0 deletions Examples/Counter/CounterSupport/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// swift-tools-version: 5.8
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "CounterSupport",
platforms: [.iOS(.v16)],
products: [
.library(
name: "CounterDomain",
targets: ["CounterDomain"]
),
.library(
name: "CounterUI",
targets: ["CounterUI"]
),
],
dependencies: [
.package(path: "../../../"),
.package(
url: "https://github.com/apple/swift-collections.git",
branch: "release/1.1"
),
],
targets: [
.target(
name: "CounterUI",
dependencies: [
"CounterDomain",
.product(name: "StateTreeImperativeUI", package: "StateTree"),
]
),
.target(
name: "CounterDomain",
dependencies: [
.product(name: "StateTree", package: "StateTree"),
.product(name: "OrderedCollections", package: "swift-collections"),
]
),
]
)
3 changes: 3 additions & 0 deletions Examples/Counter/CounterSupport/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Counter

A description of this package.
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import Foundation
import StateTree

public struct Counter: Node, Identifiable {

public let id: Int
public let shouldDelete: () -> Void
@Value public var count: Int = 0

public var emoji: Emoji {
Emoji.hash(of: id)
}

public var incrementDisabled: Bool {
count == 10
}

public var decrementDisabled: Bool {
count == -10
}

public var rules: some Rules {
OnUpdate(count) { _ in
count = max(min(10, count), -10)
}
}

public func increment() {
count += 1
}

public func decrement() {
count -= 1
}

public func delete() {
shouldDelete()
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import Foundation
import StateTree

public struct CountersList: Node {

// MARK: Lifecycle

public init() { }

// MARK: Public

@Route public var counters: [Counter] = []

public var rules: some Rules {
Serve(data: counterIDs, at: $counters) { datum in
Counter(
id: datum,
shouldDelete: {
delete(counter: datum)
}
)
}
}

public func addCounter() {
$scope.transaction {
let counter = nextCounter
counterIDs.append(counter)
nextCounter += 1
}
}

public func delete(counter id: Int) {
counterIDs.removeAll { $0 == id }
}

// MARK: Private

@Value private var counterIDs: [Int] = []
@Value private var nextCounter = 0
@Scope private var scope

}
Loading

0 comments on commit 9a56e84

Please sign in to comment.