Skip to content

Commit 10c04d2

Browse files
authored
Merge pull request #9 from skiptools/inlinecompose
Support for mixing Compose code into native UI
2 parents 708b89d + 41fd17b commit 10c04d2

2 files changed

Lines changed: 68 additions & 50 deletions

File tree

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2025 Skip
2+
//
3+
// This is free software: you can redistribute and/or modify it
4+
// under the terms of the GNU Lesser General Public License 3.0
5+
// as published by the Free Software Foundation https://fsf.org
6+
import SkipBridge
7+
import SkipUI
8+
9+
/// Embed Compose content in the SwiftUI view tree.
10+
public struct ComposeView : View {
11+
private let content: any JConvertible
12+
13+
/// Supply a block that returns a `SkipUI.ContentComposer`.
14+
public init(content: () -> any JConvertible) {
15+
self.content = content()
16+
}
17+
18+
public typealias body = Never
19+
}
20+
21+
extension ComposeView : SkipUIBridging {
22+
public var Java_view: any SkipUI.View {
23+
return SkipUI.ComposeView(bridgedContent: content)
24+
}
25+
}

Sources/SkipFuseUI/Properties/Binding.swift

Lines changed: 43 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// This is free software: you can redistribute and/or modify it
44
// under the terms of the GNU Lesser General Public License 3.0
55
// as published by the Free Software Foundation https://fsf.org
6+
import SkipBridge
67

78
@propertyWrapper @dynamicMemberLookup public struct Binding<Value> {
89
let get: () -> Value
@@ -45,39 +46,17 @@
4546
return Binding<Subject>(get: { wrappedValue[keyPath: keyPath] }, set: { wrappedValue[keyPath: keyPath] = $0 })
4647
}
4748

48-
// /// Creates a binding with a closure that reads from the binding value, and
49-
// /// a closure that applies a transaction when writing to the binding value.
50-
// ///
51-
// /// A binding conforms to Sendable only if its wrapped value type also
52-
// /// conforms to Sendable. It is always safe to pass a sendable binding
53-
// /// between different concurrency domains. However, reading from or writing
54-
// /// to a binding's wrapped value from a different concurrency domain may or
55-
// /// may not be safe, depending on how the binding was created. SwiftUI will
56-
// /// issue a warning at runtime if it detects a binding being used in a way
57-
// /// that may compromise data safety.
58-
// ///
59-
// /// For a "computed" binding created using get and set closure parameters,
60-
// /// the safety of accessing its wrapped value from a different concurrency
61-
// /// domain depends on whether those closure arguments are isolated to
62-
// /// a specific actor. For example, a computed binding with closure arguments
63-
// /// that are known (or inferred) to be isolated to the main actor must only
64-
// /// ever access its wrapped value on the main actor as well, even if the
65-
// /// binding is also sendable.
66-
// ///
67-
// /// - Parameters:
68-
// /// - get: A closure to retrieve the binding value. The closure has no
69-
// /// parameters, and returns a value.
70-
// /// - set: A closure to set the binding value. The closure has the
71-
// /// following parameters:
72-
// /// - newValue: The new value of the binding value.
73-
// /// - transaction: The transaction to apply when setting a new value.
7449
// @preconcurrency public init(get: @escaping @isolated(any) @Sendable () -> Value, set: @escaping @isolated(any) @Sendable (Value, Transaction) -> Void)
75-
//
76-
// /// The binding's transaction.
77-
// ///
78-
// /// The transaction captures the information needed to update the view when
79-
// /// the binding value changes.
80-
// public var transaction: Transaction
50+
51+
@available(*, unavailable)
52+
public var transaction: Any /* Transaction */ {
53+
get {
54+
fatalError()
55+
}
56+
set {
57+
fatalError()
58+
}
59+
}
8160
}
8261

8362
extension Binding {
@@ -162,21 +141,35 @@ extension Binding : BidirectionalCollection where Value : BidirectionalCollectio
162141
extension Binding : RandomAccessCollection where Value : MutableCollection, Value : RandomAccessCollection {
163142
}
164143

165-
//@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
166-
//extension Binding {
167-
//
168-
// /// Specifies a transaction for the binding.
169-
// ///
170-
// /// - Parameter transaction : An instance of a ``Transaction``.
171-
// ///
172-
// /// - Returns: A new binding.
173-
// public func transaction(_ transaction: Transaction) -> Binding<Value>
174-
//
175-
// /// Specifies an animation to perform when the binding value changes.
176-
// ///
177-
// /// - Parameter animation: An animation sequence performed when the binding
178-
// /// value changes.
179-
// ///
180-
// /// - Returns: A new binding.
181-
// public func animation(_ animation: Animation? = .default) -> Binding<Value>
182-
//}
144+
extension Binding {
145+
@available(*, unavailable)
146+
public func transaction(_ transaction: Any /* Transaction */) -> Binding<Value> {
147+
fatalError()
148+
}
149+
150+
@available(*, unavailable)
151+
public func animation(_ animation: Any? = nil /* Animation? = .default */) -> Binding<Value> {
152+
fatalError()
153+
}
154+
}
155+
156+
extension Binding : JConvertible, JObjectProtocol {
157+
public static func fromJavaObject(_ ptr: JavaObjectPointer?, options: JConvertibleOptions) -> Self {
158+
let get_java: JavaObjectPointer = try! ptr!.call(method: Java_SkipUIBinding_get_methodID, options: options, args: [])
159+
let set_java: JavaObjectPointer = try! ptr!.call(method: Java_SkipUIBinding_set_methodID, options: options, args: [])
160+
let get_swift: () -> Value = SwiftClosure0.closure(forJavaObject: get_java, options: options)!
161+
let set_swift: (Value) -> Void = SwiftClosure1.closure(forJavaObject: set_java, options: options)!
162+
return Binding(get: get_swift, set: set_swift)
163+
}
164+
165+
public func toJavaObject(options: JConvertibleOptions) -> JavaObjectPointer? {
166+
let get_java = SwiftClosure0.javaObject(for: self.get, options: options)!.toJavaParameter(options: options)
167+
let set_java = SwiftClosure1.javaObject(for: self.set, options: options)!.toJavaParameter(options: options)
168+
return try! Java_SkipUIBinding.create(ctor: Java_SkipUIBinding_constructor_methodID, options: options, args: [get_java, set_java])
169+
}
170+
}
171+
172+
private let Java_SkipUIBinding = try! JClass(name: "skip/ui/Binding")
173+
private let Java_SkipUIBinding_constructor_methodID = Java_SkipUIBinding.getMethodID(name: "<init>", sig: "(Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;)V")!
174+
private let Java_SkipUIBinding_get_methodID = Java_SkipUIBinding.getMethodID(name: "getGet", sig: "()Lkotlin/jvm/functions/Function0;")!
175+
private let Java_SkipUIBinding_set_methodID = Java_SkipUIBinding.getMethodID(name: "getSet", sig: "()Lkotlin/jvm/functions/Function1;")!

0 commit comments

Comments
 (0)