Skip to content

Commit

Permalink
Open source
Browse files Browse the repository at this point in the history
  • Loading branch information
tattn committed Oct 16, 2023
1 parent b66f62a commit bb2cf52
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 90 deletions.
4 changes: 4 additions & 0 deletions app/xcode/Sources/VCamBridge/ExternalStateBinding.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,8 @@ private var reloaders: [UUID: Reloader] = [:]
wrappedValue[keyPath: keyPath] = newValue.wrappedValue
}
}

public static func constant(_ value: Value) -> Self {
.init(id: UUID(uuidString: "2546C91C-12FB-4BC2-A7C0-F1A7DA7318C0")!, get: { value }, set: { _ in })
}
}
4 changes: 4 additions & 0 deletions app/xcode/Sources/VCamBridge/UniBridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
import SwiftUI
public final class UniBridge {
public static let shared = UniBridge()
#if DEBUG
public init() {}
#else
private init() {}
#endif
public enum IntType: Int32 {
case lensFlare = 0
case facialExpression = 1
Expand Down
21 changes: 8 additions & 13 deletions app/xcode/Sources/VCamUI/RootContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,18 @@
//

import SwiftUI
import VCamBridge

public struct RootContentView<VCamUI: View, MenuBottomView: View, Toolbar: View>: View {
public init(vcamUI: VCamUI, menuBottomView: MenuBottomView, toolbar: Toolbar, unityView: NSView, interactable: Bool) {
self.vcamUI = vcamUI
public struct RootContentView<MenuBottomView: View>: View {
public init(menuBottomView: MenuBottomView, unityView: NSView, interactable: ExternalStateBinding<Bool> = .init(.interactable)) {
self.menuBottomView = menuBottomView
self.toolbar = toolbar
self.unityView = unityView
self.interactable = interactable
self._interactable = interactable
}

let vcamUI: VCamUI
let menuBottomView: MenuBottomView
let toolbar: Toolbar
let unityView: NSView
let interactable: Bool
@ExternalStateBinding(.interactable) private var interactable

public var body: some View {
if interactable {
Expand All @@ -36,15 +33,15 @@ public struct RootContentView<VCamUI: View, MenuBottomView: View, Toolbar: View>

VSplitView {
HStack(alignment: .bottom, spacing: 0) {
toolbar
VCamMainToolbar()
UnityView(unityView: unityView)
.equatable()
.frame(maxWidth: .infinity)
}
.frame(maxWidth: .infinity)
.layoutPriority(1)

vcamUI
VCamContentView()
.onTapGesture {
unityView.window?.makeFirstResponder(nil)
NotificationCenter.default.post(name: .unfocusObject, object: nil)
Expand Down Expand Up @@ -88,11 +85,9 @@ private struct UnityContainerView: NSViewRepresentable {
struct RootContentView_Previews: PreviewProvider {
static var previews: some View {
RootContentView(
vcamUI: Color.red,
menuBottomView: Color.blue,
toolbar: Color.yellow,
unityView: NSView(),
interactable: true
interactable: .constant(true)
)
}
}
31 changes: 7 additions & 24 deletions app/xcode/Sources/VCamUI/Toolbar/VCamMainToolbar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,7 @@ import SwiftUI
import VCamEntity

public struct VCamMainToolbar: View {
public init(photoPicker: VCamMainToolbarBackgroundColorPicker, emojiPicker: VCamMainToolbarEmojiPicker, motionPicker: VCamMainToolbarMotionPicker, blendShapePicker: VCamMainToolbarBlendShapePicker) {
self.photoPicker = photoPicker
self.emojiPicker = emojiPicker
self.motionPicker = motionPicker
self.blendShapePicker = blendShapePicker
}

let photoPicker: VCamMainToolbarBackgroundColorPicker
let emojiPicker: VCamMainToolbarEmojiPicker
let motionPicker: VCamMainToolbarMotionPicker
let blendShapePicker: VCamMainToolbarBlendShapePicker
public init() {}

@State private var isPhotoPopover = false
@State private var isEmojiPickerPopover = false
Expand All @@ -38,7 +28,7 @@ public struct VCamMainToolbar: View {
}
.popover(isPresented: $isPhotoPopover) {
VCamPopoverContainer(L10n.background.key) {
photoPicker
VCamMainToolbarBackgroundColorPicker()
}
.environment(\.locale, locale)
}
Expand All @@ -62,7 +52,7 @@ public struct VCamMainToolbar: View {
}
}
} content: {
emojiPicker
VCamMainToolbarEmojiPicker()
}
.environment(\.locale, locale)
.frame(width: 240)
Expand All @@ -75,7 +65,7 @@ public struct VCamMainToolbar: View {
}
.popover(isPresented: $isMotionPickerPopover) {
VCamPopoverContainerWithWindow(L10n.motion.key) {
motionPicker
VCamMainToolbarMotionPicker()
}
.environment(\.locale, locale)
.frame(width: 240)
Expand All @@ -88,7 +78,7 @@ public struct VCamMainToolbar: View {
}
.popover(isPresented: $isBlendShapePickerPopover) {
VCamPopoverContainerWithWindow(L10n.facialExpression.key) {
blendShapePicker
VCamMainToolbarBlendShapePicker()
}
.environment(\.locale, locale)
.frame(width: 280, height: 150)
Expand All @@ -115,13 +105,6 @@ public struct VCamMainToolbar: View {
}
}

struct VCamMainToolbar_Previews: PreviewProvider {
static var previews: some View {
VCamMainToolbar(
photoPicker: VCamMainToolbarBackgroundColorPicker(backgroundColor: .constant(.red)),
emojiPicker: VCamMainToolbarEmojiPicker(),
motionPicker: VCamMainToolbarMotionPicker(motionHello: {}, motionBye: { .constant(false) }, motionJump: {}, motionYear: {}, motionWhat: {}, motionWin: {}, motionNod: { .constant(false) }, motionShakeHead: { .constant(false) }, motionShakeBody: { .constant(false) }, motionRun: { .constant(false) }),
blendShapePicker: VCamMainToolbarBlendShapePicker(blendShapes: [], selectedBlendShape: { .constant(nil) })
)
}
#Preview {
VCamMainToolbar()
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@

import SwiftUI
import VCamUIFoundation
import VCamBridge

public struct VCamMainToolbarBackgroundColorPicker: View {
public init(backgroundColor: Binding<Color>) {
self._backgroundColor = backgroundColor
public init(
backgroundColor: ExternalStateBinding<Color> = .init(.backgroundColor)
) {
_backgroundColor = backgroundColor
}

@Binding var backgroundColor: Color
@ExternalStateBinding(.backgroundColor) private var backgroundColor: Color

public var body: some View {
GroupBox {
Expand All @@ -29,8 +32,6 @@ public struct VCamMainToolbarBackgroundColorPicker: View {
}
}

struct VCamMainToolbarPhotoPicker_Previews: PreviewProvider {
static var previews: some View {
VCamMainToolbarBackgroundColorPicker(backgroundColor: .constant(.red))
}
#Preview {
VCamMainToolbarBackgroundColorPicker(backgroundColor: .constant(.red))
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,24 @@
//

import SwiftUI
import VCamBridge

public struct VCamMainToolbarBlendShapePicker: View {
public init(blendShapes: [String], selectedBlendShape: () -> Binding<String?>) {
public init(blendShapes: [String] = UniBridge.cachedBlendShapes) {
self.blendShapes = blendShapes
self._selectedBlendShape = selectedBlendShape()
}

let blendShapes: [String]
@Binding var selectedBlendShape: String?
@UniReload private var reload: Void
@ExternalStateBinding(.currentBlendShape) private var currentBlendShape

public var body: some View {
ScrollView(.vertical, showsIndicators: true) {
GroupBox {
LazyVGrid(columns: [GridItem(.adaptive(minimum: 60))]) {
ForEach(blendShapes) { blendShape in
HoverToggle(text: blendShape, isOn: $selectedBlendShape.map(
HoverToggle(text: blendShape, isOn: $currentBlendShape.map(
get: { blendShape == $0 },
set: { $0 ? blendShape : nil }
set: { $0 ? blendShape : "" }
))
}
}
Expand Down Expand Up @@ -73,8 +72,6 @@ extension VCamMainToolbarBlendShapePicker: MacWindow {
}
}

struct VCamMainToolbarBlendShapePicker_Previews: PreviewProvider {
static var previews: some View {
VCamMainToolbarBlendShapePicker(blendShapes: ["natural", "joy"], selectedBlendShape: { .constant("joy") })
}
#Preview {
VCamMainToolbarBlendShapePicker(blendShapes: ["natural", "joy"])
}
73 changes: 37 additions & 36 deletions app/xcode/Sources/VCamUI/Toolbar/VCamMainToolbarMotionPicker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,49 +6,39 @@
//

import SwiftUI
import VCamBridge

public struct VCamMainToolbarMotionPicker: View {
public init(motionHello: @escaping () -> Void, motionBye: @escaping () -> Binding<Bool>, motionJump: @escaping () -> Void, motionYear: @escaping () -> Void, motionWhat: @escaping () -> Void, motionWin: @escaping () -> Void, motionNod: @escaping () -> Binding<Bool>, motionShakeHead: @escaping () -> Binding<Bool>, motionShakeBody: @escaping () -> Binding<Bool>, motionRun: @escaping () -> Binding<Bool>) {
self.motionHello = motionHello
self.motionBye = motionBye
self.motionJump = motionJump
self.motionYear = motionYear
self.motionWhat = motionWhat
self.motionWin = motionWin
self.motionNod = motionNod
self.motionShakeHead = motionShakeHead
self.motionShakeBody = motionShakeBody
self.motionRun = motionRun
}
public init() {}

let motionHello: () -> Void
let motionBye: () -> Binding<Bool>
let motionJump: () -> Void
let motionYear: () -> Void
let motionWhat: () -> Void
let motionWin: () -> Void
let motionNod: () -> Binding<Bool>
let motionShakeHead: () -> Binding<Bool>
let motionShakeBody: () -> Binding<Bool>
let motionRun: () -> Binding<Bool>
@UniAction(.motionHello) var motionHello
@ExternalStateBinding(.motionBye) var motionBye
@UniAction(.motionJump) var motionJump
@UniAction(.motionYear) var motionYear
@UniAction(.motionWhat) var motionWhat
@UniAction(.motionWin) var motionWin
@ExternalStateBinding(.motionNod) var motionNod
@ExternalStateBinding(.motionShakeHead) var motionShakeHead
@ExternalStateBinding(.motionShakeBody) var motionShakeBody
@ExternalStateBinding(.motionRun) var motionRun

@Environment(\.nsWindow) var nsWindow
@UniReload private var reload: Void

public var body: some View {
GroupBox {
LazyVGrid(columns: [GridItem(.adaptive(minimum: 80))], spacing: 2) {
button(key: L10n.hi.key, action: motionHello)
toggle(key: L10n.bye.key, isOn: motionBye())
button(key: L10n.jump.key, action: motionJump)
button(key: L10n.cheer.key, action: motionYear)
button(key: L10n.what.key, action: motionWhat)
button(key: L10n.hi.key, action: { motionHello() })
toggle(key: L10n.bye.key, isOn: $motionBye.workaround())
button(key: L10n.jump.key, action: { motionJump() })
button(key: L10n.cheer.key, action: { motionYear() })
button(key: L10n.what.key, action: { motionWhat() })
Group {
button(key: L10n.pose.key, action: motionWin)
toggle(key: L10n.nod.key, isOn: motionNod())
toggle(key: L10n.no.key, isOn: motionShakeHead())
toggle(key: L10n.shudder.key, isOn: motionShakeBody())
toggle(key: L10n.run.key, isOn: motionRun())
button(key: L10n.pose.key, action: { motionWin() })
toggle(key: L10n.nod.key, isOn: $motionNod.workaround())
toggle(key: L10n.no.key, isOn: $motionShakeHead.workaround())
toggle(key: L10n.shudder.key, isOn: $motionShakeBody.workaround())
toggle(key: L10n.run.key, isOn: $motionRun.workaround())
}
}
}
Expand Down Expand Up @@ -100,9 +90,20 @@ extension VCamMainToolbarMotionPicker: MacWindow {
}
}

struct VCamMainToolbarMotionPicker_Previews: PreviewProvider {
static var previews: some View {
VCamMainToolbarMotionPicker(motionHello: {}, motionBye: { .constant(false) }, motionJump: {}, motionYear: {}, motionWhat: {}, motionWin: {}, motionNod: { .constant(false) }, motionShakeHead: { .constant(false) }, motionShakeBody: { .constant(false) }, motionRun: { .constant(false) })
.frame(width: 240)
private extension Binding {
// The state updates with a slight delay, so wait a bit before refreshing the UI
func workaround() -> Self {
map(get: { $0 }, set: {
Task {
try? await Task.sleep(nanoseconds: NSEC_PER_MSEC * 300)
UniReload.Reloader.shared.objectWillChange.send()
}
return $0
})
}
}

#Preview {
VCamMainToolbarMotionPicker()
.frame(width: 240)
}

0 comments on commit bb2cf52

Please sign in to comment.