add onboarding flow
This commit is contained in:
parent
bd5b630c04
commit
ffdb1b607f
|
@ -1,4 +1,4 @@
|
|||
[gd_scene load_steps=16 format=3 uid="uid://eecv28y6jxk4"]
|
||||
[gd_scene load_steps=17 format=3 uid="uid://eecv28y6jxk4"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://clc5dre31iskm" path="res://addons/godot-xr-tools/xr/start_xr.tscn" id="1_i4c04"]
|
||||
[ext_resource type="Script" path="res://content/main.gd" id="1_uvrd4"]
|
||||
|
@ -11,6 +11,7 @@
|
|||
[ext_resource type="PackedScene" uid="uid://c3kdssrmv84kv" path="res://content/ui/menu/menu.tscn" id="8_du83w"]
|
||||
[ext_resource type="PackedScene" uid="uid://lrehk38exd5n" path="res://content/system/keyboard/keyboard.tscn" id="9_e5n3p"]
|
||||
[ext_resource type="PackedScene" uid="uid://cbemihbxkd4ll" path="res://content/system/house/house.tscn" id="9_np6mw"]
|
||||
[ext_resource type="PackedScene" uid="uid://bhyddd1f0ry1x" path="res://content/ui/onboarding/onboarding.tscn" id="12_uq2nj"]
|
||||
|
||||
[sub_resource type="Sky" id="Sky_vhymk"]
|
||||
sky_material = ExtResource("5_wgwf8")
|
||||
|
@ -83,4 +84,7 @@ transform = Transform3D(0.499999, -0.000139169, -6.50204e-05, 5.24307e-05, 0.353
|
|||
|
||||
[node name="House" parent="." instance=ExtResource("9_np6mw")]
|
||||
|
||||
[node name="Onboarding" parent="." instance=ExtResource("12_uq2nj")]
|
||||
transform = Transform3D(0.999999, -1.39632e-11, 0, 9.48097e-12, 0.999999, 0, 0, 0, 0.999999, -0.529594, 0.820154, -0.600147)
|
||||
|
||||
[editable path="XROrigin3D/XRControllerLeft"]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
extends Node3D
|
||||
|
||||
const VoiceAssistant = preload ("res://lib/home_apis/voice_handler.gd")
|
||||
const sample_hold = preload ("res://lib/utils/sample_hold.gd")
|
||||
const Chat = preload ("./chat.gd")
|
||||
|
||||
|
@ -19,18 +20,27 @@ var effect: AudioEffectCapture
|
|||
@onready var camera = $"/root/Main/XROrigin3D/XRCamera3D"
|
||||
|
||||
var running := false
|
||||
var voice_assistant: VoiceAssistant
|
||||
|
||||
func _ready():
|
||||
var index = AudioServer.get_bus_index("Record")
|
||||
effect = AudioServer.get_bus_effect(index, 0)
|
||||
|
||||
if !HomeApi.has_connected():
|
||||
await HomeApi.on_connect
|
||||
|
||||
voice_assistant = HomeApi.get_voice_assistant()
|
||||
|
||||
if voice_assistant == null:
|
||||
return
|
||||
|
||||
finish()
|
||||
|
||||
audio_timer.timeout.connect(func():
|
||||
HomeApi.api.assist_handler.send_data(PackedByteArray())
|
||||
voice_assistant.send_data(PackedByteArray())
|
||||
)
|
||||
|
||||
HomeApi.api.assist_handler.on_wake_word.connect(func(text):
|
||||
voice_assistant.on_wake_word.connect(func(_text):
|
||||
loader.visible=true
|
||||
chat_user.visible=false
|
||||
chat_assistant.visible=false
|
||||
|
@ -40,24 +50,24 @@ func _ready():
|
|||
running=true
|
||||
)
|
||||
|
||||
HomeApi.api.assist_handler.on_stt_message.connect(func(text):
|
||||
voice_assistant.on_stt_message.connect(func(text):
|
||||
loader.visible=false
|
||||
chat_user.visible=true
|
||||
chat_user.text=text
|
||||
)
|
||||
HomeApi.api.assist_handler.on_tts_message.connect(func(text):
|
||||
voice_assistant.on_tts_message.connect(func(text):
|
||||
chat_assistant.visible=true
|
||||
chat_assistant.text=text
|
||||
)
|
||||
|
||||
HomeApi.api.assist_handler.on_tts_sound.connect(func(audio):
|
||||
voice_assistant.on_tts_sound.connect(func(audio):
|
||||
audio_player_3d.stream=audio
|
||||
audio_player_3d.play()
|
||||
visual_timer.start()
|
||||
running=false
|
||||
)
|
||||
|
||||
HomeApi.api.assist_handler.on_error.connect(func():
|
||||
voice_assistant.on_error.connect(func():
|
||||
running=false
|
||||
finish()
|
||||
)
|
||||
|
@ -101,9 +111,9 @@ func _process(_delta):
|
|||
|
||||
if max_amplitude > input_threshold:
|
||||
if audio_timer.is_stopped():
|
||||
HomeApi.api.assist_handler.start_wakeword()
|
||||
voice_assistant.start_wakeword()
|
||||
|
||||
audio_timer.start()
|
||||
|
||||
if audio_timer.is_stopped() == false:
|
||||
HomeApi.api.assist_handler.send_data(data)
|
||||
voice_assistant.send_data(data)
|
||||
|
|
|
@ -3,7 +3,7 @@ extends XRCamera3D
|
|||
var last_room = null
|
||||
|
||||
func _physics_process(_delta):
|
||||
if HomeApi.api.has_integration():
|
||||
if HomeApi.has_integration():
|
||||
update_room()
|
||||
|
||||
func update_room():
|
||||
|
@ -11,8 +11,8 @@ func update_room():
|
|||
|
||||
if room != last_room:
|
||||
if room:
|
||||
HomeApi.api.update_room(room.name)
|
||||
HomeApi.update_room(room.name)
|
||||
last_room = room
|
||||
else:
|
||||
HomeApi.api.update_room("outside")
|
||||
HomeApi.update_room("outside")
|
||||
last_room = null
|
|
@ -5,8 +5,8 @@ extends StaticBody3D
|
|||
var max_message = 30
|
||||
var messages: Array = ["aaa", "bbb"]
|
||||
|
||||
func log(text: String) -> void:
|
||||
messages.push_front(text)
|
||||
func log(text: Variant) -> void:
|
||||
messages.push_front(str(text))
|
||||
|
||||
if messages.size() > max_message:
|
||||
messages.pop_back()
|
||||
|
|
43
app/content/ui/onboarding/onboarding.gd
Normal file
43
app/content/ui/onboarding/onboarding.gd
Normal file
|
@ -0,0 +1,43 @@
|
|||
extends Node3D
|
||||
|
||||
@onready var getting_started_button = $GettingStartedButton
|
||||
@onready var close_button = $CloseButton
|
||||
@onready var camera = $"/root/Main/XROrigin3D/XRCamera3D"
|
||||
var next_new_position = global_position
|
||||
|
||||
func _ready():
|
||||
if Store.settings.is_loaded() == false:
|
||||
await Store.settings.on_loaded
|
||||
|
||||
if (Store.settings.url != ""&&Store.settings.url != null)||Store.settings.onboarding_complete:
|
||||
close()
|
||||
return
|
||||
|
||||
getting_started_button.on_button_down.connect(func():
|
||||
OS.shell_open("https://docs.immersive-home.org/")
|
||||
)
|
||||
|
||||
close_button.on_button_down.connect(func():
|
||||
close()
|
||||
)
|
||||
|
||||
EventSystem.on_slow_tick.connect(_slow_tick)
|
||||
|
||||
func close():
|
||||
Store.settings.onboarding_complete = true
|
||||
Store.settings.save_local()
|
||||
queue_free()
|
||||
|
||||
func _slow_tick(delta):
|
||||
var new_position = camera.global_position + camera.global_transform.basis.z * - 0.5
|
||||
|
||||
if next_new_position.distance_to(new_position) > 0.2:
|
||||
next_new_position = new_position
|
||||
var new_direction = Basis.looking_at((camera.global_position - new_position) * - 1)
|
||||
|
||||
var tween = create_tween()
|
||||
tween.set_parallel(true)
|
||||
tween.set_trans(Tween.TransitionType.TRANS_QUAD)
|
||||
|
||||
tween.tween_property(self, "global_position", new_position, 0.6)
|
||||
tween.tween_property(self, "global_transform:basis", new_direction, 0.6)
|
68
app/content/ui/onboarding/onboarding.tscn
Normal file
68
app/content/ui/onboarding/onboarding.tscn
Normal file
|
@ -0,0 +1,68 @@
|
|||
[gd_scene load_steps=6 format=3 uid="uid://bhyddd1f0ry1x"]
|
||||
|
||||
[ext_resource type="Script" path="res://content/ui/onboarding/onboarding.gd" id="1_k4yvw"]
|
||||
[ext_resource type="Material" uid="uid://bujy3egn1oqac" path="res://assets/materials/pri-500.material" id="2_aleti"]
|
||||
[ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/components/button/button.tscn" id="3_hlpow"]
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_nfwtf"]
|
||||
size = Vector3(0.5, 0.3, 0.01)
|
||||
|
||||
[sub_resource type="BoxMesh" id="BoxMesh_yknqs"]
|
||||
size = Vector3(0.5, 0.3, 0.01)
|
||||
|
||||
[node name="Onboarding" type="StaticBody3D"]
|
||||
script = ExtResource("1_k4yvw")
|
||||
|
||||
[node name="Label3D2" type="Label3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.23, -0.1, 0.006)
|
||||
pixel_size = 0.001
|
||||
text = "Getting Started"
|
||||
font_size = 18
|
||||
outline_size = 0
|
||||
horizontal_alignment = 0
|
||||
vertical_alignment = 0
|
||||
autowrap_mode = 3
|
||||
width = 470.0
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||
shape = SubResource("BoxShape3D_nfwtf")
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
||||
material_override = ExtResource("2_aleti")
|
||||
mesh = SubResource("BoxMesh_yknqs")
|
||||
|
||||
[node name="GettingStartedLabel" type="Label3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.23, 0.14, 0.006)
|
||||
pixel_size = 0.001
|
||||
text = "Hey!
|
||||
|
||||
This app is still early in development and still has a lot of rough edges. Things might break or are sometimes difficult to use, this will improve the more the app ages.
|
||||
|
||||
If this is the first time you try the app, please first read through the \"Getting Started\" Guide below."
|
||||
font_size = 18
|
||||
outline_size = 0
|
||||
horizontal_alignment = 0
|
||||
vertical_alignment = 0
|
||||
autowrap_mode = 3
|
||||
width = 470.0
|
||||
|
||||
[node name="GettingStartedButton" parent="." instance=ExtResource("3_hlpow")]
|
||||
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, -0.05, -0.11, 0)
|
||||
label = "open_in_new"
|
||||
icon = true
|
||||
|
||||
[node name="CloseButton" parent="." instance=ExtResource("3_hlpow")]
|
||||
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0.21, -0.11, 0)
|
||||
label = "done"
|
||||
icon = true
|
||||
|
||||
[node name="CloseLabel" type="Label3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.06, -0.1, 0.006)
|
||||
pixel_size = 0.001
|
||||
text = "Understood"
|
||||
font_size = 18
|
||||
outline_size = 0
|
||||
horizontal_alignment = 0
|
||||
vertical_alignment = 0
|
||||
autowrap_mode = 3
|
||||
width = 470.0
|
|
@ -3,6 +3,7 @@ extends Node
|
|||
|
||||
const Hass = preload ("res://lib/home_apis/hass/hass.gd")
|
||||
const HassWebSocket = preload ("res://lib/home_apis/hass_ws/hass.gd")
|
||||
const VoiceAssistant = preload ("res://lib/home_apis/voice_handler.gd")
|
||||
|
||||
const apis = {
|
||||
"hass": Hass,
|
||||
|
@ -96,7 +97,26 @@ func watch_state(entity: String, callback: Callable):
|
|||
assert(has_connected(), "Not connected")
|
||||
return api.watch_state(entity, callback)
|
||||
|
||||
func _notification(what):
|
||||
if what == NOTIFICATION_WM_CLOSE_REQUEST||what == NOTIFICATION_WM_GO_BACK_REQUEST:
|
||||
# Store.house.save_local()
|
||||
pass
|
||||
## Returns true if the adapter has an integration in the home automation system
|
||||
## allowing to send the room position of the headset.
|
||||
func has_integration() -> bool:
|
||||
if has_connected() == false||api.has_method("has_integration") == false:
|
||||
return false
|
||||
|
||||
return api.has_integration()
|
||||
|
||||
## Updates the room position of the headset in the home automation system
|
||||
func update_room(room: String) -> void:
|
||||
if has_connected() == false||api.has_method("update_room") == false:
|
||||
return
|
||||
|
||||
api.update_room(room)
|
||||
|
||||
## Returns the VoiceHandler if the adapter has a voice assistant
|
||||
func get_voice_assistant() -> VoiceAssistant:
|
||||
assert(has_connected(), "Not connected")
|
||||
|
||||
if api.has_method("get_voice_assistant") == false:
|
||||
return null
|
||||
|
||||
return api.get_voice_assistant()
|
|
@ -5,6 +5,6 @@ const SettingsStore = preload ("res://lib/stores/settings.gd")
|
|||
const HouseStore = preload ("res://lib/stores/house.gd")
|
||||
const DevicesStore = preload ("res://lib/stores/devices.gd")
|
||||
|
||||
var settings = SettingsStore.new()
|
||||
var house = HouseStore.new()
|
||||
var devices = DevicesStore.new()
|
||||
var settings := SettingsStore.new()
|
||||
var house := HouseStore.new()
|
||||
var devices := DevicesStore.new()
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
const HASS_API = preload ("../hass.gd")
|
||||
extends VoiceHandler
|
||||
|
||||
signal on_wake_word(wake_word: String)
|
||||
signal on_stt_message(message: String)
|
||||
signal on_tts_message(message: String)
|
||||
signal on_tts_sound(sound: AudioStreamMP3)
|
||||
signal on_error()
|
||||
const HASS_API = preload ("../hass.gd")
|
||||
const VoiceHandler = preload ("res://lib/home_apis/voice_handler.gd")
|
||||
|
||||
var api: HASS_API
|
||||
var pipe_running := false
|
||||
|
@ -36,9 +33,6 @@ var tts_sound = null:
|
|||
func _init(hass: HASS_API):
|
||||
self.api = hass
|
||||
|
||||
func on_connect():
|
||||
pass
|
||||
|
||||
func start_wakeword():
|
||||
if pipe_running:
|
||||
return
|
||||
|
|
|
@ -121,7 +121,6 @@ func start_subscriptions():
|
|||
|
||||
func handle_connect():
|
||||
integration_handler.on_connect()
|
||||
assist_handler.on_connect()
|
||||
connected = true
|
||||
on_connect.emit()
|
||||
|
||||
|
@ -282,4 +281,7 @@ func update_room(room: String):
|
|||
})
|
||||
|
||||
if response.status == Promise.Status.RESOLVED:
|
||||
pass
|
||||
pass
|
||||
|
||||
func get_voice_assistant():
|
||||
return assist_handler
|
||||
|
|
11
app/lib/home_apis/voice_handler.gd
Normal file
11
app/lib/home_apis/voice_handler.gd
Normal file
|
@ -0,0 +1,11 @@
|
|||
signal on_wake_word(wake_word: String)
|
||||
signal on_stt_message(message: String)
|
||||
signal on_tts_message(message: String)
|
||||
signal on_tts_sound(sound: AudioStreamMP3)
|
||||
signal on_error()
|
||||
|
||||
func start_wakeword() -> bool:
|
||||
return false
|
||||
|
||||
func send_data(data: PackedByteArray) -> void:
|
||||
pass
|
|
@ -11,6 +11,9 @@ var token: String = ""
|
|||
## If the voice assistant should be enabled
|
||||
var voice_assistant: bool = false
|
||||
|
||||
## If the onboarding process has been completed
|
||||
var onboarding_complete: bool = false
|
||||
|
||||
func _init():
|
||||
_save_path = "user://settings.json"
|
||||
|
||||
|
@ -18,4 +21,5 @@ func clear():
|
|||
type = "HASS_WS"
|
||||
url = ""
|
||||
token = ""
|
||||
voice_assistant = false
|
||||
voice_assistant = false
|
||||
onboarding_complete = false
|
|
@ -77,8 +77,11 @@ func load_local(path=_save_path):
|
|||
|
||||
var save_file = FileAccess.open(path, FileAccess.READ)
|
||||
|
||||
# In case that there is no store file yet
|
||||
if save_file == null:
|
||||
return false
|
||||
_loaded = true
|
||||
on_loaded.emit()
|
||||
return true
|
||||
|
||||
var json_text = save_file.get_as_text()
|
||||
var save_data = VariantSerializer.parse_value(JSON.parse_string(json_text))
|
||||
|
|
Loading…
Reference in New Issue
Block a user