-
-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
753 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 12 additions & 0 deletions
12
app/xcode/Sources/VCamUI/Settings/VCamSettingExperimentView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// | ||
// VCamSettingExperimentView.swift | ||
// | ||
// | ||
// Created by Tatsuya Tanaka on 2023/10/21. | ||
// | ||
|
||
import SwiftUI | ||
|
||
public enum VCamSettingExperimentView { | ||
public static var make: () -> AnyView = { fatalError() } | ||
} |
105 changes: 105 additions & 0 deletions
105
app/xcode/Sources/VCamUI/Settings/VCamSettingTrackingView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
// | ||
// VCamSettingTrackingView.swift | ||
// | ||
// | ||
// Created by Tatsuya Tanaka on 2023/02/14. | ||
// | ||
|
||
import SwiftUI | ||
import AVFoundation | ||
import VCamEntity | ||
import VCamCamera | ||
import VCamTracking | ||
import VCamBridge | ||
|
||
public struct VCamSettingTrackingView: View { | ||
public init() {} | ||
|
||
@AppStorage(key: .cameraFps) private var cameraFps | ||
@AppStorage(key: .moveXIntensity) private var moveXIntensity | ||
@AppStorage(key: .eyeTrackingIntensityX) private var eyeTrackingIntensityX | ||
@AppStorage(key: .eyeTrackingIntensityY) private var eyeTrackingIntensityY | ||
@AppStorage(key: .useVowelEstimation) private var useVowelEstimation | ||
@AppStorage(key: .useEyeTracking) private var useEyeTracking | ||
@AppStorage(key: .fingerTrackingOpenIntensity) private var fingerTrackingOpenIntensity | ||
@AppStorage(key: .fingerTrackingCloseIntensity) private var fingerTrackingCloseIntensity | ||
#if ENABLE_MOCOPI | ||
@AppStorage(key: .integrationMocopi) private var integrationMocopi | ||
#endif | ||
|
||
@ExternalStateBinding(.lipSyncMicIntensity) private var lipSyncMicIntensity | ||
@ExternalStateBinding(.shoulderRotationWeight) private var shoulderRotationWeight | ||
@ExternalStateBinding(.swivelOffset) private var swivelOffset | ||
|
||
@StateObject private var toggleWorkaround = ToggleWorkaround() | ||
|
||
public var body: some View { | ||
VStack { | ||
VCamTrackingView() | ||
TrackingDeviceView() | ||
|
||
GroupBox { | ||
VStack(alignment: .leading) { | ||
Toggle(isOn: $useVowelEstimation) { | ||
Text(L10n.useVowelEstimation.key, bundle: .localize) | ||
} | ||
} | ||
.frame(maxWidth: .infinity, alignment: .leading) | ||
} | ||
|
||
GroupBox { | ||
Form { | ||
ValueEditField(L10n.lipSyncSensitivity.key, value: $lipSyncMicIntensity, type: .slider(0.1...3)) | ||
ValueEditField(L10n.fpsCamera.key, value: $cameraFps.map(), type: .slider(1...60) { isEditing in | ||
guard !isEditing else { return } | ||
Tracking.shared.avatarCameraManager.setFPS(cameraFps) | ||
}) | ||
} | ||
} | ||
|
||
GroupBox { | ||
Form { | ||
ValueEditField(L10n.easeOfBodyMovement.key, value: $moveXIntensity.map(), type: .slider(0.1...3)) | ||
ValueEditField(L10n.shoulderRotationWeight.key, value: $shoulderRotationWeight, type: .slider(0.0...1)) | ||
ValueEditField(L10n.swivelOffset.key, value: $swivelOffset, type: .slider(0.0...30)) | ||
} | ||
} | ||
#if ENABLE_MOCOPI | ||
.disabled(integrationMocopi) | ||
#endif | ||
GroupBox { | ||
VStack(alignment: .leading) { | ||
Toggle(isOn: $useEyeTracking) { | ||
Text(L10n.trackEyes.key, bundle: .localize) | ||
} | ||
Group { | ||
ValueEditField(L10n.eyesHorizontalSensitivity.key, value: $eyeTrackingIntensityX.map(), type: .slider(0...10)) | ||
ValueEditField(L10n.eyesVerticalSensitivity.key, value: $eyeTrackingIntensityY.map(), type: .slider(0...10)) | ||
} | ||
.disabled(!useEyeTracking) | ||
} | ||
} | ||
GroupBox { | ||
VStack { | ||
ValueEditField(L10n.easeOfOpeningFingers.key, value: $fingerTrackingOpenIntensity.map(), type: .slider(0.1...3)) | ||
ValueEditField(L10n.easeOfCloseFingers.key, value: $fingerTrackingCloseIntensity.map(), type: .slider(0.1...3)) | ||
} | ||
.frame(maxWidth: .infinity, alignment: .leading) | ||
} | ||
} | ||
.onAppear { | ||
toggleWorkaround.run() | ||
} | ||
} | ||
} | ||
|
||
private final class ToggleWorkaround: ObservableObject { | ||
// Workaround: The UI fails to refresh when using checkbox-style toggle, requiring a one-time rebuild of the UI for updates to take effect. | ||
func run() { | ||
objectWillChange.send() | ||
} | ||
} | ||
|
||
#Preview { | ||
VCamSettingTrackingView() | ||
} |
132 changes: 132 additions & 0 deletions
132
app/xcode/Sources/VCamUI/Settings/VCamSettingView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
// | ||
// VCamSettingView.swift | ||
// | ||
// | ||
// Created by Tatsuya Tanaka on 2023/02/12. | ||
// | ||
|
||
import SwiftUI | ||
import VCamEntity | ||
import VCamCamera | ||
import VCamLocalization | ||
import AVFoundation | ||
|
||
public struct VCamSettingView: View { | ||
public enum Tab: Hashable, Identifiable, CaseIterable { | ||
case general | ||
case rendering | ||
case tracking | ||
case virtualCamera | ||
case integration | ||
case experiment | ||
|
||
public var id: Self { self } | ||
|
||
var title: LocalizedStringKey { | ||
switch self { | ||
case .general: | ||
L10n.general.key | ||
case .rendering: | ||
L10n.rendering.key | ||
case .tracking: | ||
L10n.tracking.key | ||
case .virtualCamera: | ||
L10n.virtualCamera.key | ||
case .integration: | ||
L10n.integration.key | ||
case .experiment: | ||
L10n.experiment.key | ||
} | ||
} | ||
|
||
var icon: Image { | ||
switch self { | ||
case .general: | ||
Image(systemName: "hammer.fill") | ||
case .rendering: | ||
Image(systemName: "display") | ||
case .tracking: | ||
if #available(macOS 14, *) { | ||
Image(systemName: "figure") | ||
} else { | ||
Image(systemName: "figure.arms.open") | ||
} | ||
case .virtualCamera: | ||
Image(systemName: "camera.fill") | ||
case .integration: | ||
Image(systemName: "app.connected.to.app.below.fill") | ||
case .experiment: | ||
Image(systemName: "exclamationmark.triangle.fill") | ||
} | ||
} | ||
} | ||
|
||
@State var tab: Tab? | ||
|
||
@ObservedObject private var recorder = VideoRecorder.shared | ||
|
||
@AppStorage(key: .locale) var locale | ||
|
||
public init(tab: Tab = .general) { | ||
self._tab = State(initialValue: tab) | ||
} | ||
|
||
public var body: some View { | ||
HStack { | ||
List(selection: $tab) { | ||
ForEach(Tab.allCases) { tab in | ||
Label { | ||
Text(tab.title, bundle: .localize) | ||
.font(.callout) | ||
} icon: { | ||
tab.icon | ||
} | ||
} | ||
} | ||
.listStyle(.sidebar) | ||
.frame(width: 140) | ||
|
||
VStack { | ||
switch tab { | ||
case .general: | ||
VCamSettingGeneralView() | ||
case .rendering: | ||
VCamSettingRenderingView() | ||
case .tracking: | ||
VCamSettingTrackingView() | ||
case .virtualCamera: | ||
VCamSettingVirtualCameraView() | ||
case .integration: | ||
VCamSettingsIntegrationView() | ||
case .experiment: | ||
VCamSettingExperimentView.make() | ||
case nil: | ||
Text("🥹") | ||
} | ||
Spacer() | ||
} | ||
.frame(minWidth: 440) | ||
} | ||
.padding([.top, .trailing], 8) | ||
.onChange(of: tab) { newValue in | ||
if newValue == nil { | ||
tab = tab | ||
} | ||
} | ||
.environment(\.locale, locale.isEmpty ? .current : Locale(identifier: locale)) | ||
.disabled(recorder.isRecording) | ||
} | ||
} | ||
|
||
extension VCamSettingView: MacWindow { | ||
public var windowTitle: String { L10n.settings.text } | ||
|
||
public func configureWindow(_ window: NSWindow) -> NSWindow { | ||
window.level = .floating | ||
return window | ||
} | ||
} | ||
|
||
#Preview { | ||
VCamSettingView(tab: .general) | ||
} |
Oops, something went wrong.