Initialer Upload neues Unity-Projekt
This commit is contained in:
8
Assets/Oculus/Voice/Features/Dictation.meta
Normal file
8
Assets/Oculus/Voice/Features/Dictation.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eecb7c4b510d577449bb41342bbc1b23
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1bfb7ddc6964ad149808272cd3d23c6c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9ba9fc263f3e43f4980af677857ac268
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Oculus/Voice/Features/Dictation/Documentation/Samples/Dictation - Sample.asset
(Stored with Git LFS)
Normal file
BIN
Assets/Oculus/Voice/Features/Dictation/Documentation/Samples/Dictation - Sample.asset
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 94a69914db4e817499b358815448549e
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Oculus/Voice/Features/Dictation/Documentation/Samples/DictationSampleScreenShot.jpg
(Stored with Git LFS)
Normal file
BIN
Assets/Oculus/Voice/Features/Dictation/Documentation/Samples/DictationSampleScreenShot.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,92 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2891b87fce4e6014fb1b139272e49719
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Voice/Features/Dictation/Plugins.meta
Normal file
8
Assets/Oculus/Voice/Features/Dictation/Plugins.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce565818b48ace445bb96419f9c2646a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@ -0,0 +1,32 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c752b70a94dcf04498081eda98206e9c
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 1
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Android: Android
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Voice/Features/Dictation/Prefabs.meta
Normal file
8
Assets/Oculus/Voice/Features/Dictation/Prefabs.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d52e6a286831c642b5fbb7d06f80182
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Oculus/Voice/Features/Dictation/Prefabs/DictationService.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/Oculus/Voice/Features/Dictation/Prefabs/DictationService.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ba31729cfe8be2642a8bcac537765e59
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Voice/Features/Dictation/Samples.meta
Normal file
8
Assets/Oculus/Voice/Features/Dictation/Samples.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 284ad7ac52e5ea445b37746d1c53b1b0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e09021722fb9eb449a5277e47da3f54e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Oculus/Voice/Features/Dictation/Samples/Dictation/Dictation Sample - WitConfiguration.asset
(Stored with Git LFS)
Normal file
BIN
Assets/Oculus/Voice/Features/Dictation/Samples/Dictation/Dictation Sample - WitConfiguration.asset
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cf747878b0776f44884853a7fe2ea4c8
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8ee7784e909f62f46bc0446a0a0fe0ae
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,84 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Skybox
|
||||
m_Shader: {fileID: 106, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ShaderKeywords: _SUNDISK_HIGH_QUALITY
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BumpMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailAlbedoMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailNormalMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _EmissionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OcclusionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ParallaxMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Floats:
|
||||
- _AtmosphereThickness: 1.54
|
||||
- _BumpScale: 1
|
||||
- _Cutoff: 0.5
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _Exposure: 1
|
||||
- _GlossMapScale: 1
|
||||
- _Glossiness: 0.5
|
||||
- _GlossyReflections: 1
|
||||
- _Metallic: 0
|
||||
- _Mode: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _SunDisk: 2
|
||||
- _SunSize: 0
|
||||
- _SunSizeConvergence: 5
|
||||
- _UVSec: 0
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _GroundColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _SkyTint: {r: 0.3773585, g: 0.2076738, b: 0, a: 1}
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a179d7f204d6abd488033e6085dd7043
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 49b48c0b655307b4fa5b71c105fd7930
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Oculus/Voice/Features/Dictation/Samples/Dictation/Scenes/DictationSampleScene.unity
(Stored with Git LFS)
Normal file
BIN
Assets/Oculus/Voice/Features/Dictation/Samples/Dictation/Scenes/DictationSampleScene.unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3a8c4fc64087e144b845d1afe890c5ba
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d36adaaad49194346a8d99f8ff0ab6e9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using Meta.WitAi.Dictation;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace Meta.Voice.Samples.Dictation
|
||||
{
|
||||
public class DictationActivation : MonoBehaviour
|
||||
{
|
||||
[FormerlySerializedAs("dictation")]
|
||||
[SerializeField] private DictationService _dictation;
|
||||
|
||||
public void ToggleActivation()
|
||||
{
|
||||
if (_dictation.MicActive)
|
||||
{
|
||||
_dictation.Deactivate();
|
||||
}
|
||||
else
|
||||
{
|
||||
_dictation.Activate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8304dcac029408f42893d86756f3cc30
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
|
||||
namespace Meta.Voice.Samples.Dictation
|
||||
{
|
||||
public class SimpleLabelResizer : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private TextMeshProUGUI _label;
|
||||
private string _text;
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
_label = gameObject.GetComponent<TextMeshProUGUI>();
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (_label == null)
|
||||
{
|
||||
_label = gameObject.GetComponent<TextMeshProUGUI>();
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!string.Equals(_text, _label.text))
|
||||
{
|
||||
RefreshSize();
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshSize()
|
||||
{
|
||||
_text = _label.text;
|
||||
float preferredHeight = _label.preferredHeight;
|
||||
_label.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, preferredHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 514ba6b315e97374e81991951a802240
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "Meta.Voice.Samples.Dictation",
|
||||
"references": [
|
||||
"GUID:1c28d8b71ced07540b7c271537363cc6",
|
||||
"GUID:4504b1a6e0fdcc3498c30b266e4a63bf",
|
||||
"GUID:910a956078d2ff4429c717211dcfaecb",
|
||||
"GUID:6055be8ebefd69e48b49212b09b47b2f"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 33e189c6e0423344cba4faa96a127602
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Voice/Features/Dictation/Scripts.meta
Normal file
8
Assets/Oculus/Voice/Features/Dictation/Scripts.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2a72e9375732a1c439d3e991372e6a25
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ad3861f68f5f6ec4e8ccc1ddfbd7129c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System.IO;
|
||||
using Meta.WitAi;
|
||||
using Meta.WitAi.Dictation;
|
||||
using Meta.WitAi.Windows;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Voice.Dictation
|
||||
{
|
||||
[CustomEditor(typeof(AppDictationExperience))]
|
||||
public class AppDictationExperienceEditor : Editor
|
||||
{
|
||||
[SerializeField] private string transcribeFile;
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
|
||||
if (EditorApplication.isPlaying)
|
||||
{
|
||||
GUILayout.BeginVertical(EditorStyles.helpBox);
|
||||
GUILayout.Label("File Transcriber");
|
||||
GUILayout.BeginHorizontal();
|
||||
transcribeFile = EditorGUILayout.TextField(transcribeFile);
|
||||
if (GUILayout.Button("Browse", GUILayout.Width(75)))
|
||||
{
|
||||
var pickedFile = EditorUtility.OpenFilePanel("Select File", "", "wav");
|
||||
if (!string.IsNullOrEmpty(pickedFile))
|
||||
{
|
||||
transcribeFile = pickedFile;
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
if (File.Exists(transcribeFile) && GUILayout.Button("Transcribe"))
|
||||
{
|
||||
var dictationService = ((AppDictationExperience)target).GetComponent<WitDictation>();
|
||||
dictationService.TranscribeFile(transcribeFile);
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 294403565ca76cd44a221a07f911e80d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 95c8c3f7c517467f9a7d4365ca7f1f19
|
||||
timeCreated: 1656510929
|
||||
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using Meta.WitAi.Configuration;
|
||||
using Meta.WitAi.Data;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Voice.Dictation.Data
|
||||
{
|
||||
public class AppDictationDataCreation
|
||||
{
|
||||
[MenuItem("Assets/Create/Voice SDK/Add App Dictation Experience to Scene", false, 100)]
|
||||
public static void AddVoiceCommandServiceToScene()
|
||||
{
|
||||
var witGo = new GameObject();
|
||||
witGo.name = "App Dictation Experience";
|
||||
var wit = witGo.AddComponent<AppDictationExperience>();
|
||||
wit.RuntimeDictationConfiguration = new WitDictationRuntimeConfiguration
|
||||
{
|
||||
witConfiguration = WitDataCreation.FindDefaultWitConfig()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 55d3bf29671d34b9c84160431ee2429d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c6000f2708bf4d37b50eddbac06db445
|
||||
timeCreated: 1656458466
|
||||
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Voice.Dictation.Inspectors
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(WitDictationRuntimeConfigDrawer))]
|
||||
public class WitDictationRuntimeConfigDrawer : PropertyDrawer
|
||||
{
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
base.OnGUI(position, property, label);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ad073cad346af44a281dd01c4d8a4a3c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "VoiceSDK.Dictation.Editor",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:7fc7076089fdfbc4399cba40cc3b0dd6",
|
||||
"GUID:910a956078d2ff4429c717211dcfaecb",
|
||||
"GUID:fa958eb9f0171754fb207d563a15ddfa",
|
||||
"GUID:4504b1a6e0fdcc3498c30b266e4a63bf",
|
||||
"GUID:1c28d8b71ced07540b7c271537363cc6"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fb043033254d90e46b4abaa2879909ea
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0babb0488968124c85712d1bf12da58
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c188f83b2845a4c6db26cf96dc004cf2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ea91106e590de2945938dd234262b37e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Voice.Dictation.Configuration
|
||||
{
|
||||
[Serializable]
|
||||
public class DictationConfiguration
|
||||
{
|
||||
[Tooltip("Re-open the mic after the final transcription. Useful for long form content/messaging.")]
|
||||
public bool multiPhrase;
|
||||
[Tooltip("Hint about the scenario that the user is dictating. Default to package name. In the future we might have messaging, search, general, etc")]
|
||||
public string scenario = "default";
|
||||
[Tooltip("Input types: text_default: Normal text, numeric: Numbers, email: Email addresses")]
|
||||
public string inputType = "text_default";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 07b07eeddd4fd7847a488c8fb590b5e9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6b7302946fb0f1e4299eb699e30c7449
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,40 @@
|
||||
namespace Oculus.Voice.Dictation.Listeners
|
||||
{
|
||||
public interface DictationListener
|
||||
{
|
||||
/// <summary>
|
||||
/// Called when dictation has started
|
||||
/// </summary>
|
||||
void OnStart(DictationListener listener);
|
||||
|
||||
/// <summary>
|
||||
/// Called when mic level changes. Used for building UI.
|
||||
/// </summary>
|
||||
/// <param name="micLevel"></param>
|
||||
void OnMicAudioLevel(float micLevel);
|
||||
|
||||
/// <summary>
|
||||
/// Called with current predicted transcription. Could change as user speaks.
|
||||
/// </summary>
|
||||
/// <param name="transcription"></param>
|
||||
void OnPartialTranscription(string transcription);
|
||||
|
||||
/// <summary>
|
||||
/// Final transcription of what the user has said
|
||||
/// </summary>
|
||||
/// <param name="transcription"></param>
|
||||
void OnFinalTranscription(string transcription);
|
||||
|
||||
/// <summary>
|
||||
/// Called when there was an error with the dictation service
|
||||
/// </summary>
|
||||
/// <param name="errorType">The type of error encountered</param>
|
||||
/// <param name="errorMessage">Human readable message describing the error</param>
|
||||
void OnError(string errorType, string errorMessage);
|
||||
|
||||
/// <summary>
|
||||
/// Called when the dictation session is done
|
||||
/// </summary>
|
||||
void OnStopped(DictationListener listener);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 809d25c26f051e44991a37caa328aa7a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0768efab3897ba744a6ad727b7bc28ee
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,458 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Oculus SDK License Agreement (the "License");
|
||||
* you may not use the Oculus SDK except in compliance with the License,
|
||||
* which is provided at the time of installation or download, or which
|
||||
* otherwise accompanies this software in either electronic or hard copy form.
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://developer.oculus.com/licenses/oculussdk/
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, the Oculus SDK
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Meta.Voice;
|
||||
using Meta.WitAi;
|
||||
using Meta.WitAi.Configuration;
|
||||
using Meta.WitAi.Data.Configuration;
|
||||
using Meta.WitAi.Dictation;
|
||||
using Meta.WitAi.Dictation.Data;
|
||||
using Meta.WitAi.Interfaces;
|
||||
using Meta.WitAi.Requests;
|
||||
using Oculus.Voice.Dictation.Bindings.Android;
|
||||
using Oculus.VoiceSDK.Utilities;
|
||||
using Oculus.Voice.Core.Bindings.Android.PlatformLogger;
|
||||
using Oculus.Voice.Core.Bindings.Interfaces;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Voice.Dictation
|
||||
{
|
||||
public class AppDictationExperience : DictationService, IWitRuntimeConfigProvider, IWitConfigurationProvider
|
||||
{
|
||||
[SerializeField] private WitDictationRuntimeConfiguration runtimeConfiguration;
|
||||
[Tooltip("Uses platform dictation service instead of accessing wit directly from within the application.")]
|
||||
[SerializeField] private bool usePlatformServices;
|
||||
|
||||
[Tooltip("Dictation will not fallback to Wit if platform dictation is not available. Not applicable in Unity Editor")]
|
||||
[SerializeField] private bool doNotFallbackToWit;
|
||||
[Tooltip("Enables logs related to the interaction to be displayed on console")]
|
||||
[SerializeField] private bool enableConsoleLogging;
|
||||
|
||||
public WitRuntimeConfiguration RuntimeConfiguration => runtimeConfiguration;
|
||||
public WitDictationRuntimeConfiguration RuntimeDictationConfiguration
|
||||
{
|
||||
get => runtimeConfiguration;
|
||||
set => runtimeConfiguration = value;
|
||||
}
|
||||
public WitConfiguration Configuration => RuntimeConfiguration?.witConfiguration;
|
||||
|
||||
private IDictationService _dictationServiceImpl;
|
||||
private IVoiceSDKLogger _voiceSDKLogger;
|
||||
/// <summary>
|
||||
/// True if the user currently has requested dictation to be active. This will remain true until a Deactivate
|
||||
/// method is called and we will reactivate when the mic stops as a result.
|
||||
/// </summary>
|
||||
private bool _isActive;
|
||||
|
||||
private DictationSession _activeSession;
|
||||
private WitRequestOptions _activeRequestOptions;
|
||||
|
||||
public DictationSession ActiveSession => _activeSession;
|
||||
public WitRequestOptions ActiveRequestOptions => _activeRequestOptions;
|
||||
|
||||
public event Action OnInitialized;
|
||||
|
||||
private static string PACKAGE_VERSION => VoiceSDKConstants.SdkVersion;
|
||||
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
public bool HasPlatformIntegrations => usePlatformServices && _dictationServiceImpl is PlatformDictationImpl;
|
||||
#else
|
||||
public bool HasPlatformIntegrations => false;
|
||||
#endif
|
||||
|
||||
public bool UsePlatformIntegrations
|
||||
{
|
||||
get => usePlatformServices;
|
||||
set
|
||||
{
|
||||
// If we're trying to turn on platform services and they're not currently active we
|
||||
// will forcably reinit and try to set the state.
|
||||
if (usePlatformServices != value || HasPlatformIntegrations != value)
|
||||
{
|
||||
usePlatformServices = value;
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
VLog.D($"{(usePlatformServices ? "Enabling" : "Disabling")} platform integration.");
|
||||
InitDictation();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool DoNotFallbackToWit
|
||||
{
|
||||
get => doNotFallbackToWit;
|
||||
set => doNotFallbackToWit = value;
|
||||
}
|
||||
|
||||
private void InitDictation()
|
||||
{
|
||||
// Check voice sdk version
|
||||
if (string.IsNullOrEmpty(PACKAGE_VERSION))
|
||||
{
|
||||
VLog.E("No SDK Version Set");
|
||||
}
|
||||
// Clean up if we're switching to native C# wit impl
|
||||
if (!UsePlatformIntegrations)
|
||||
{
|
||||
if (_dictationServiceImpl is PlatformDictationImpl)
|
||||
{
|
||||
((PlatformDictationImpl) _dictationServiceImpl).Disconnect();
|
||||
}
|
||||
|
||||
if (_voiceSDKLogger is VoiceSDKPlatformLoggerImpl)
|
||||
{
|
||||
try
|
||||
{
|
||||
((VoiceSDKPlatformLoggerImpl)_voiceSDKLogger).Disconnect();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
VLog.E($"Disconnection error: {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
var loggerImpl = new VoiceSDKPlatformLoggerImpl();
|
||||
loggerImpl.Connect(PACKAGE_VERSION);
|
||||
_voiceSDKLogger = loggerImpl;
|
||||
|
||||
if (UsePlatformIntegrations)
|
||||
{
|
||||
VLog.D("Checking platform dictation capabilities...");
|
||||
var platformDictationImpl = new PlatformDictationImpl(this);
|
||||
platformDictationImpl.OnServiceNotAvailableEvent += OnPlatformServiceNotAvailable;
|
||||
platformDictationImpl.Connect(PACKAGE_VERSION);
|
||||
if (platformDictationImpl.PlatformSupportsDictation)
|
||||
{
|
||||
_dictationServiceImpl = platformDictationImpl;
|
||||
_dictationServiceImpl.DictationEvents = DictationEvents;
|
||||
_dictationServiceImpl.TelemetryEvents = TelemetryEvents;
|
||||
platformDictationImpl.SetDictationRuntimeConfiguration(RuntimeDictationConfiguration);
|
||||
VLog.D("Dictation platform init complete");
|
||||
_voiceSDKLogger.IsUsingPlatformIntegration = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
OnPlatformServiceNotAvailable();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RevertToWitDictation();
|
||||
}
|
||||
#else
|
||||
_voiceSDKLogger = new VoiceSDKConsoleLoggerImpl();
|
||||
RevertToWitDictation();
|
||||
#endif
|
||||
_voiceSDKLogger.WitApplication = RuntimeDictationConfiguration?.witConfiguration?.GetLoggerAppId();
|
||||
_voiceSDKLogger.ShouldLogToConsole = enableConsoleLogging;
|
||||
|
||||
OnInitialized?.Invoke();
|
||||
}
|
||||
|
||||
private void OnPlatformServiceNotAvailable()
|
||||
{
|
||||
#if !UNITY_EDITOR
|
||||
if (DoNotFallbackToWit)
|
||||
{
|
||||
VLog.D("Platform dictation service unavailable. Falling back to WitDictation is disabled");
|
||||
DictationEvents.OnError?.Invoke("Platform dictation unavailable", "Platform dictation service is not available");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
VLog.D("Platform dictation service unavailable. Falling back to WitDictation");
|
||||
RevertToWitDictation();
|
||||
}
|
||||
|
||||
private void OnDictationServiceNotAvailable()
|
||||
{
|
||||
VLog.D("Dictation service unavailable");
|
||||
DictationEvents.OnError?.Invoke("Dictation unavailable", "Dictation service is not available");
|
||||
}
|
||||
|
||||
private void RevertToWitDictation()
|
||||
{
|
||||
WitDictation witDictation = GetComponent<WitDictation>();
|
||||
if (null == witDictation)
|
||||
{
|
||||
witDictation = gameObject.AddComponent<WitDictation>();
|
||||
witDictation.hideFlags = HideFlags.HideInInspector;
|
||||
}
|
||||
|
||||
witDictation.RuntimeConfiguration = RuntimeDictationConfiguration;
|
||||
witDictation.DictationEvents = DictationEvents;
|
||||
witDictation.TelemetryEvents = TelemetryEvents;
|
||||
_dictationServiceImpl = witDictation;
|
||||
VLog.D("WitDictation init complete");
|
||||
_voiceSDKLogger.IsUsingPlatformIntegration = false;
|
||||
}
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
if (MicPermissionsManager.HasMicPermission())
|
||||
{
|
||||
InitDictation();
|
||||
}
|
||||
else
|
||||
{
|
||||
MicPermissionsManager.RequestMicPermission((e) => InitDictation());
|
||||
}
|
||||
|
||||
DictationEvents.OnRequestInitialized.AddListener(OnRequestInit);
|
||||
DictationEvents.OnStartListening.AddListener(OnStarted);
|
||||
DictationEvents.OnStoppedListening.AddListener(OnStopped);
|
||||
DictationEvents.OnComplete.AddListener(OnComplete);
|
||||
DictationEvents.OnDictationSessionStarted.AddListener(OnDictationSessionStarted);
|
||||
DictationEvents.OnPartialTranscription.AddListener(OnPartialTranscription);
|
||||
DictationEvents.OnFullTranscription.AddListener(OnFullTranscription);
|
||||
TelemetryEvents.OnAudioTrackerFinished.AddListener(OnAudioDurationTrackerFinished);
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
#if UNITY_ANDROID
|
||||
if (_dictationServiceImpl is PlatformDictationImpl platformDictationImpl)
|
||||
{
|
||||
platformDictationImpl.Disconnect();
|
||||
}
|
||||
|
||||
if (_voiceSDKLogger is VoiceSDKPlatformLoggerImpl loggerImpl)
|
||||
{
|
||||
loggerImpl.Disconnect();
|
||||
}
|
||||
#endif
|
||||
_dictationServiceImpl = null;
|
||||
_voiceSDKLogger = null;
|
||||
DictationEvents.OnRequestInitialized.RemoveListener(OnRequestInit);
|
||||
DictationEvents.OnStartListening.RemoveListener(OnStarted);
|
||||
DictationEvents.OnStoppedListening.RemoveListener(OnStopped);
|
||||
DictationEvents.OnComplete.RemoveListener(OnComplete);
|
||||
DictationEvents.OnDictationSessionStarted.RemoveListener(OnDictationSessionStarted);
|
||||
DictationEvents.OnPartialTranscription.RemoveListener(OnPartialTranscription);
|
||||
DictationEvents.OnFullTranscription.RemoveListener(OnFullTranscription);
|
||||
TelemetryEvents.OnAudioTrackerFinished.RemoveListener(OnAudioDurationTrackerFinished);
|
||||
base.OnDisable();
|
||||
}
|
||||
|
||||
#region DictationService properties
|
||||
|
||||
public override bool Active => _dictationServiceImpl != null && _dictationServiceImpl.Active;
|
||||
public override bool IsRequestActive => _dictationServiceImpl != null && _dictationServiceImpl.IsRequestActive;
|
||||
|
||||
public override ITranscriptionProvider TranscriptionProvider
|
||||
{
|
||||
get => _dictationServiceImpl.TranscriptionProvider;
|
||||
set => _dictationServiceImpl.TranscriptionProvider = value;
|
||||
|
||||
}
|
||||
public override bool MicActive => null != _dictationServiceImpl && _dictationServiceImpl.MicActive;
|
||||
protected override bool ShouldSendMicData => RuntimeConfiguration.sendAudioToWit ||
|
||||
null == TranscriptionProvider;
|
||||
#endregion
|
||||
|
||||
#region DictationService APIs
|
||||
/// <summary>
|
||||
/// Toggle dictation activation from on->off or off->on depending on the current active state.
|
||||
/// </summary>
|
||||
public void Toggle()
|
||||
{
|
||||
if(Active) Deactivate();
|
||||
else Activate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Activate the microphone and send data to Wit for NLU processing.
|
||||
/// </summary>
|
||||
public override VoiceServiceRequest Activate(WitRequestOptions requestOptions, VoiceServiceRequestEvents requestEvents)
|
||||
{
|
||||
if (_dictationServiceImpl == null)
|
||||
{
|
||||
OnDictationServiceNotAvailable();
|
||||
return null;
|
||||
}
|
||||
if (!_isActive)
|
||||
{
|
||||
_activeSession = new DictationSession();
|
||||
DictationEvents.OnDictationSessionStarted.Invoke(_activeSession);
|
||||
}
|
||||
_isActive = true;
|
||||
return _dictationServiceImpl.Activate(requestOptions, requestEvents);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Activates immediately and starts sending data to the server. This will not wait for min wake threshold
|
||||
/// </summary>
|
||||
/// <param name="options"></param>
|
||||
public override VoiceServiceRequest ActivateImmediately(WitRequestOptions requestOptions, VoiceServiceRequestEvents requestEvents)
|
||||
{
|
||||
if (_dictationServiceImpl == null)
|
||||
{
|
||||
OnDictationServiceNotAvailable();
|
||||
return null;
|
||||
}
|
||||
if (!_isActive)
|
||||
{
|
||||
_activeSession = new DictationSession();
|
||||
DictationEvents.OnDictationSessionStarted.Invoke(_activeSession);
|
||||
}
|
||||
_isActive = true;
|
||||
return _dictationServiceImpl.ActivateImmediately(requestOptions, requestEvents);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deactivates. If a transcription is in progress the network request will complete and any additional
|
||||
/// transcription values will be returned.
|
||||
/// </summary>
|
||||
public override void Deactivate()
|
||||
{
|
||||
if (_dictationServiceImpl == null)
|
||||
{
|
||||
OnDictationServiceNotAvailable();
|
||||
return;
|
||||
}
|
||||
|
||||
_isActive = false;
|
||||
_dictationServiceImpl.Deactivate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deactivates and ignores any pending transcription content.
|
||||
/// </summary>
|
||||
public override void Cancel()
|
||||
{
|
||||
if (_dictationServiceImpl == null)
|
||||
{
|
||||
OnDictationServiceNotAvailable();
|
||||
return;
|
||||
}
|
||||
|
||||
_dictationServiceImpl.Cancel();
|
||||
CleanupSession();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Listeners for logging
|
||||
void OnRequestInit(VoiceServiceRequest request)
|
||||
{
|
||||
_activeRequestOptions = request?.Options;
|
||||
|
||||
_voiceSDKLogger.LogInteractionStart(request?.Options?.RequestId, "dictation");
|
||||
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
_voiceSDKLogger.LogAnnotation("clientSDKVersion", PACKAGE_VERSION);
|
||||
#endif
|
||||
_voiceSDKLogger.LogAnnotation("minWakeThreshold",
|
||||
RuntimeConfiguration?.soundWakeThreshold.ToString(CultureInfo.InvariantCulture));
|
||||
_voiceSDKLogger.LogAnnotation("minKeepAliveTimeSec",
|
||||
RuntimeConfiguration?.minKeepAliveTimeInSeconds.ToString(CultureInfo.InvariantCulture));
|
||||
_voiceSDKLogger.LogAnnotation("minTranscriptionKeepAliveTimeSec",
|
||||
RuntimeConfiguration?.minTranscriptionKeepAliveTimeInSeconds.ToString(CultureInfo.InvariantCulture));
|
||||
_voiceSDKLogger.LogAnnotation("maxRecordingTime",
|
||||
RuntimeConfiguration?.maxRecordingTime.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
void OnStarted()
|
||||
{
|
||||
_voiceSDKLogger.LogInteractionPoint("startedListening");
|
||||
}
|
||||
|
||||
void OnStopped()
|
||||
{
|
||||
_voiceSDKLogger.LogInteractionPoint("stoppedListening");
|
||||
|
||||
if (RuntimeDictationConfiguration.dictationConfiguration.multiPhrase && _isActive)
|
||||
{
|
||||
Activate(_activeRequestOptions);
|
||||
}
|
||||
}
|
||||
|
||||
void OnDictationSessionStarted(DictationSession session)
|
||||
{
|
||||
if (session is PlatformDictationSession platformDictationSession)
|
||||
{
|
||||
_activeSession = session;
|
||||
_voiceSDKLogger.LogAnnotation("platformInteractionId", platformDictationSession.platformSessionId);
|
||||
}
|
||||
}
|
||||
|
||||
void OnAudioDurationTrackerFinished(long timestamp, double audioDuration)
|
||||
{
|
||||
_voiceSDKLogger.LogAnnotation("adt_duration", audioDuration.ToString(CultureInfo.InvariantCulture));
|
||||
_voiceSDKLogger.LogAnnotation("adt_finished", timestamp.ToString());
|
||||
}
|
||||
|
||||
void OnPartialTranscription(string text)
|
||||
{
|
||||
_voiceSDKLogger.LogFirstTranscriptionTime();
|
||||
}
|
||||
|
||||
void OnFullTranscription(string text)
|
||||
{
|
||||
_voiceSDKLogger.LogInteractionPoint("fullTranscriptionTime");
|
||||
}
|
||||
|
||||
void OnComplete(VoiceServiceRequest request)
|
||||
{
|
||||
if (request.State == VoiceRequestState.Failed)
|
||||
{
|
||||
VLog.E($"Dictation Request Failed\nError: {request.Results.Message}");
|
||||
_voiceSDKLogger.LogInteractionEndFailure(request.Results.Message);
|
||||
}
|
||||
else if (request.State == VoiceRequestState.Canceled)
|
||||
{
|
||||
VLog.W($"Dictation Request Canceled\nMessage: {request.Results.Message}");
|
||||
_voiceSDKLogger.LogInteractionEndFailure("aborted");
|
||||
}
|
||||
else
|
||||
{
|
||||
VLog.D($"Dictation Request Success");
|
||||
var tokens = request.ResponseData?["speech"]?["tokens"];
|
||||
if (tokens != null)
|
||||
{
|
||||
int speechTokensLength = tokens.Count;
|
||||
string speechLength = request.ResponseData["speech"]["tokens"][speechTokensLength - 1]?["end"]?.Value;
|
||||
_voiceSDKLogger.LogAnnotation("audioLength", speechLength);
|
||||
}
|
||||
_voiceSDKLogger.LogInteractionEndSuccess();
|
||||
}
|
||||
if (!_isActive)
|
||||
{
|
||||
DictationEvents.OnDictationSessionStopped?.Invoke(_activeSession);
|
||||
CleanupSession();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Cleanup
|
||||
|
||||
private void CleanupSession()
|
||||
{
|
||||
_activeSession = null;
|
||||
_activeRequestOptions = null;
|
||||
_isActive = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f6da0ed72f4541d7b52607891bafa6f3
|
||||
timeCreated: 1652467620
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 86035a05c90f4460fbac04a0c49be3d7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 99387caa63da84115b622a0d8cdfeaa9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Oculus SDK License Agreement (the "License");
|
||||
* you may not use the Oculus SDK except in compliance with the License,
|
||||
* which is provided at the time of installation or download, or which
|
||||
* otherwise accompanies this software in either electronic or hard copy form.
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://developer.oculus.com/licenses/oculussdk/
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, the Oculus SDK
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using Meta.WitAi;
|
||||
using Meta.WitAi.Configuration;
|
||||
using Oculus.Voice.Dictation.Configuration;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Voice.Dictation.Bindings.Android
|
||||
{
|
||||
public class DictationConfigurationBinding
|
||||
{
|
||||
private readonly WitDictationRuntimeConfiguration _runtimeConfiguration;
|
||||
private readonly DictationConfiguration _dictationConfiguration;
|
||||
private readonly int MAX_PLATFORM_SUPPORTED_RECORDING_TIME_SECONDS = 300;
|
||||
|
||||
public DictationConfigurationBinding(WitDictationRuntimeConfiguration runtimeConfiguration)
|
||||
{
|
||||
if (null == runtimeConfiguration)
|
||||
{
|
||||
// No config defined, use the default configuration.
|
||||
VLog.W("No dictation config has been defined. Using the default configuration.");
|
||||
_dictationConfiguration = new DictationConfiguration();
|
||||
}
|
||||
else
|
||||
{
|
||||
_dictationConfiguration = runtimeConfiguration.dictationConfiguration;
|
||||
_runtimeConfiguration = runtimeConfiguration;
|
||||
}
|
||||
}
|
||||
|
||||
public AndroidJavaObject ToJavaObject()
|
||||
{
|
||||
AndroidJavaObject jo = new AndroidJavaObject("com.oculus.assistant.api.voicesdk.dictation.PlatformDictationConfiguration");
|
||||
jo.Set("multiPhrase", _dictationConfiguration.multiPhrase);
|
||||
jo.Set("scenario", _dictationConfiguration.scenario);
|
||||
jo.Set("inputType", _dictationConfiguration.inputType);
|
||||
if (_runtimeConfiguration != null)
|
||||
{
|
||||
int maxRecordingTime = (int) _runtimeConfiguration.maxRecordingTime;
|
||||
if (maxRecordingTime < 0)
|
||||
{
|
||||
maxRecordingTime = MAX_PLATFORM_SUPPORTED_RECORDING_TIME_SECONDS;
|
||||
}
|
||||
jo.Set("interactionTimeoutSeconds", maxRecordingTime);
|
||||
}
|
||||
|
||||
return jo;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c72e9e84ab9e87741986d6efe576e0d9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Oculus SDK License Agreement (the "License");
|
||||
* you may not use the Oculus SDK except in compliance with the License,
|
||||
* which is provided at the time of installation or download, or which
|
||||
* otherwise accompanies this software in either electronic or hard copy form.
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://developer.oculus.com/licenses/oculussdk/
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, the Oculus SDK
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using UnityEngine;
|
||||
using Meta.WitAi;
|
||||
using Meta.WitAi.Dictation;
|
||||
using Meta.WitAi.Dictation.Data;
|
||||
using Meta.WitAi.Dictation.Events;
|
||||
|
||||
namespace Oculus.Voice.Dictation.Bindings.Android
|
||||
{
|
||||
public class DictationListenerBinding : AndroidJavaProxy
|
||||
{
|
||||
private IDictationService _dictationService;
|
||||
private IServiceEvents _serviceEvents;
|
||||
private DictationEvents DictationEvents => _dictationService.DictationEvents;
|
||||
|
||||
public DictationListenerBinding(IDictationService dictationService, IServiceEvents serviceEvents)
|
||||
: base("com.oculus.assistant.api.voicesdk.dictation.PlatformDictationListener")
|
||||
{
|
||||
_dictationService = dictationService;
|
||||
_serviceEvents = serviceEvents;
|
||||
}
|
||||
|
||||
public void onStart(string sessionId)
|
||||
{
|
||||
DictationEvents.OnStartListening?.Invoke();
|
||||
DictationSession session = new PlatformDictationSession()
|
||||
{
|
||||
dictationService = _dictationService,
|
||||
platformSessionId = sessionId
|
||||
};
|
||||
}
|
||||
|
||||
public void onMicAudioLevel(string sessionId, int micLevel)
|
||||
{
|
||||
DictationEvents.OnMicAudioLevelChanged?.Invoke(micLevel / 100.0f);
|
||||
}
|
||||
|
||||
public void onPartialTranscription(string sessionId, string transcription)
|
||||
{
|
||||
DictationEvents.OnPartialTranscription?.Invoke(transcription);
|
||||
}
|
||||
|
||||
public void onFinalTranscription(string sessionId, string transcription)
|
||||
{
|
||||
DictationEvents.OnFullTranscription?.Invoke(transcription);
|
||||
}
|
||||
|
||||
public void onError(string sessionId, string errorType, string errorMessage)
|
||||
{
|
||||
DictationEvents.OnError?.Invoke(errorType, errorMessage);
|
||||
}
|
||||
|
||||
public void onStopped(string sessionId)
|
||||
{
|
||||
DictationEvents.OnStoppedListening?.Invoke();
|
||||
DictationSession session = new PlatformDictationSession()
|
||||
{
|
||||
dictationService = _dictationService,
|
||||
platformSessionId = sessionId
|
||||
};
|
||||
}
|
||||
|
||||
public void onServiceNotAvailable(string error, string message)
|
||||
{
|
||||
VLog.W("Platform dictation service is not available");
|
||||
_serviceEvents.OnServiceNotAvailable(error, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9ae8a1a01ce0f484eafa3e39954356dc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Oculus SDK License Agreement (the "License");
|
||||
* you may not use the Oculus SDK except in compliance with the License,
|
||||
* which is provided at the time of installation or download, or which
|
||||
* otherwise accompanies this software in either electronic or hard copy form.
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://developer.oculus.com/licenses/oculussdk/
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, the Oculus SDK
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace Oculus.Voice.Dictation.Bindings.Android
|
||||
{
|
||||
public interface IServiceEvents
|
||||
{
|
||||
void OnServiceNotAvailable(string error, string message);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d37d74b88e6244ad83c9242662e8dd7c
|
||||
timeCreated: 1655489373
|
||||
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Oculus SDK License Agreement (the "License");
|
||||
* you may not use the Oculus SDK except in compliance with the License,
|
||||
* which is provided at the time of installation or download, or which
|
||||
* otherwise accompanies this software in either electronic or hard copy form.
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://developer.oculus.com/licenses/oculussdk/
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, the Oculus SDK
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Meta.WitAi.Configuration;
|
||||
using Meta.WitAi.Dictation;
|
||||
using Meta.WitAi.Dictation.Events;
|
||||
using Meta.WitAi.Events;
|
||||
using Meta.WitAi.Interfaces;
|
||||
using Meta.WitAi.Requests;
|
||||
using Meta.WitAi.Utilities;
|
||||
using Oculus.Voice.Core.Bindings.Android;
|
||||
using Oculus.Voice.Dictation.Configuration;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace Oculus.Voice.Dictation.Bindings.Android
|
||||
{
|
||||
public class PlatformDictationImpl : BaseAndroidConnectionImpl<PlatformDictationSDKBinding>, IDictationService, IServiceEvents
|
||||
{
|
||||
private readonly IDictationService _baseService;
|
||||
private bool _serviceAvailable = true;
|
||||
private WitDictationRuntimeConfiguration _dictationRuntimeConfiguration;
|
||||
public PlatformDictationImpl(IDictationService dictationService)
|
||||
: base("com.oculus.assistant.api.unity.dictation.UnityDictationServiceFragment")
|
||||
{
|
||||
_baseService = dictationService;
|
||||
}
|
||||
|
||||
private DictationListenerBinding _listenerBinding;
|
||||
|
||||
public bool PlatformSupportsDictation => service.IsSupported && _serviceAvailable;
|
||||
public bool Active => service.Active;
|
||||
public bool IsRequestActive => service.IsRequestActive;
|
||||
public bool MicActive => service.Active;
|
||||
public ITranscriptionProvider TranscriptionProvider { get; set; }
|
||||
|
||||
public DictationEvents DictationEvents
|
||||
{
|
||||
get => _baseService.DictationEvents;
|
||||
set => _baseService.DictationEvents = value;
|
||||
}
|
||||
|
||||
public TelemetryEvents TelemetryEvents
|
||||
{
|
||||
get => _baseService.TelemetryEvents;
|
||||
set => _baseService.TelemetryEvents = value;
|
||||
}
|
||||
|
||||
public Action OnServiceNotAvailableEvent;
|
||||
|
||||
public override void Connect(string version)
|
||||
{
|
||||
base.Connect(version);
|
||||
_listenerBinding = new DictationListenerBinding(this, this);
|
||||
service.SetListener(_listenerBinding);
|
||||
}
|
||||
|
||||
public override void Disconnect()
|
||||
{
|
||||
base.Disconnect();
|
||||
}
|
||||
|
||||
public void SetDictationRuntimeConfiguration(WitDictationRuntimeConfiguration configuration)
|
||||
{
|
||||
_dictationRuntimeConfiguration = configuration;
|
||||
}
|
||||
|
||||
private void Activate()
|
||||
{
|
||||
service.StartDictation(new DictationConfigurationBinding(_dictationRuntimeConfiguration));
|
||||
}
|
||||
|
||||
public VoiceServiceRequest Activate(WitRequestOptions requestOptions, VoiceServiceRequestEvents requestEvents)
|
||||
{
|
||||
Activate();
|
||||
return null;
|
||||
}
|
||||
|
||||
public VoiceServiceRequest ActivateImmediately(WitRequestOptions requestOptions, VoiceServiceRequestEvents requestEvents)
|
||||
{
|
||||
Activate();
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Deactivate()
|
||||
{
|
||||
service.StopDictation();
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
// TODO: T141779167
|
||||
service.StopDictation();
|
||||
}
|
||||
|
||||
public void OnServiceNotAvailable(string error, string message)
|
||||
{
|
||||
_serviceAvailable = false;
|
||||
OnServiceNotAvailableEvent?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5199f2cf269c82348a4fe76b61d885e4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Oculus SDK License Agreement (the "License");
|
||||
* you may not use the Oculus SDK except in compliance with the License,
|
||||
* which is provided at the time of installation or download, or which
|
||||
* otherwise accompanies this software in either electronic or hard copy form.
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://developer.oculus.com/licenses/oculussdk/
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, the Oculus SDK
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using UnityEngine;
|
||||
using Oculus.Voice.Core.Bindings.Android;
|
||||
|
||||
namespace Oculus.Voice.Dictation.Bindings.Android
|
||||
{
|
||||
public class PlatformDictationSDKBinding : BaseServiceBinding
|
||||
{
|
||||
public bool Active => binding.Call<bool>("isActive");
|
||||
public bool IsRequestActive => binding.Call<bool>("isRequestActive");
|
||||
public bool IsSupported => binding.Call<bool>("isSupported");
|
||||
|
||||
public PlatformDictationSDKBinding(AndroidJavaObject sdkInstance) : base(sdkInstance) {}
|
||||
|
||||
public void StartDictation(DictationConfigurationBinding configuration)
|
||||
{
|
||||
binding.Call("startDictation", configuration.ToJavaObject());
|
||||
}
|
||||
|
||||
public void StopDictation()
|
||||
{
|
||||
binding.Call("stopDictation");
|
||||
}
|
||||
|
||||
public void SetListener(DictationListenerBinding listenerBinding)
|
||||
{
|
||||
binding.Call("setListener", listenerBinding);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 41af6918ebf13234e857ebfc290db6ec
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Oculus SDK License Agreement (the "License");
|
||||
* you may not use the Oculus SDK except in compliance with the License,
|
||||
* which is provided at the time of installation or download, or which
|
||||
* otherwise accompanies this software in either electronic or hard copy form.
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://developer.oculus.com/licenses/oculussdk/
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, the Oculus SDK
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using Meta.WitAi.Dictation.Data;
|
||||
|
||||
namespace Oculus.Voice.Dictation.Bindings.Android
|
||||
{
|
||||
public class PlatformDictationSession : DictationSession
|
||||
{
|
||||
/// <summary>
|
||||
/// Session ID provided by the platform
|
||||
/// </summary>
|
||||
public string platformSessionId;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 87bac4c0262b45dcbbf302346ee10eb4
|
||||
timeCreated: 1657570862
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a5fa86a298d2494f86ac7aecc353f4c8
|
||||
timeCreated: 1656459347
|
||||
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Oculus.Voice.Dictation.Configuration;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Meta.WitAi.Configuration
|
||||
{
|
||||
[Serializable]
|
||||
public class WitDictationRuntimeConfiguration : WitRuntimeConfiguration
|
||||
{
|
||||
[Header("Dictation")]
|
||||
[SerializeField] public DictationConfiguration dictationConfiguration;
|
||||
|
||||
protected override Vector2 RecordingTimeRange => new Vector2(-1, 300);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eb3fd791afefd4a92a13c4a6149df2c0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5cdab34009d641eca671e122e8760e38
|
||||
timeCreated: 1655147987
|
||||
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "VoiceSDK.Dictation.Runtime",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:a7c32ded21d3b9b42a71cdf39f2ed8da",
|
||||
"GUID:4504b1a6e0fdcc3498c30b266e4a63bf",
|
||||
"GUID:910a956078d2ff4429c717211dcfaecb",
|
||||
"GUID:e545cc0678493234a9368f4e470c29e8",
|
||||
"GUID:1c28d8b71ced07540b7c271537363cc6"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7fc7076089fdfbc4399cba40cc3b0dd6
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Voice/Features/Hub.meta
Normal file
8
Assets/Oculus/Voice/Features/Hub.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 24b4ade232142364f8569fcf112c1c4f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Voice/Features/Hub/Scripts.meta
Normal file
8
Assets/Oculus/Voice/Features/Hub/Scripts.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 79bd2993a06d3ea47abef1290db75547
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Voice/Features/Hub/Scripts/Editor.meta
Normal file
8
Assets/Oculus/Voice/Features/Hub/Scripts/Editor.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 36165b1ffe137194cb78c4bfa33954fb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce0fdc4e4f6ccdd48abde94703ae1f18
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 69a95d9525bc5c14c8b3fb9cfe2af822
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Meta.Voice.Hub.Content
|
||||
{
|
||||
public class Sample : ScriptableObject
|
||||
{
|
||||
[Header("Content")]
|
||||
public string title;
|
||||
[TextArea]
|
||||
public string description;
|
||||
public Texture2D tileImage;
|
||||
public Texture2D screenshot;
|
||||
|
||||
[Header("Resource Paths")]
|
||||
public SceneAsset sceneReference;
|
||||
public string packageSampleName;
|
||||
public string sampleSetId;
|
||||
public float priority;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a0e3df96a2504a0085121315689deb30
|
||||
timeCreated: 1683063947
|
||||
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using Meta.Voice.Hub.Attributes;
|
||||
using Meta.Voice.Hub.Interfaces;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Meta.Voice.Hub.Content
|
||||
{
|
||||
[MetaHubPageScriptableObject]
|
||||
public class SamplesPage : ScriptableObject, IPageInfo
|
||||
{
|
||||
[SerializeField] private string _displayName;
|
||||
[SerializeField] private string _prefix;
|
||||
[SerializeField] private MetaHubContext _context;
|
||||
[SerializeField] private int _priority = 0;
|
||||
[SerializeField] private string _sampleSetId;
|
||||
|
||||
public string SampleSetId => _sampleSetId;
|
||||
public string Name => _displayName ?? name;
|
||||
public string Context => _context.Name;
|
||||
public int Priority => _priority;
|
||||
public string Prefix => _prefix;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0e9b6410559489dbe69ca4c70a9ad70
|
||||
timeCreated: 1683066838
|
||||
60
Assets/Oculus/Voice/Features/Hub/Scripts/Editor/ImagePage.cs
Normal file
60
Assets/Oculus/Voice/Features/Hub/Scripts/Editor/ImagePage.cs
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using Meta.Voice.Hub.Attributes;
|
||||
using Meta.Voice.Hub.Interfaces;
|
||||
using Meta.Voice.Hub.UIComponents;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace Meta.Voice.Hub
|
||||
{
|
||||
[MetaHubPageScriptableObject]
|
||||
public class ImagePage : ScriptableObject, IPageInfo
|
||||
{
|
||||
[SerializeField] private string _displayName;
|
||||
[SerializeField] private string _prefix;
|
||||
[SerializeField] private MetaHubContext _context;
|
||||
[SerializeField] private int _priority = 0;
|
||||
[SerializeField] [FormerlySerializedAs("image")]
|
||||
private Texture2D _image;
|
||||
|
||||
public string Name => _displayName ?? name;
|
||||
public string Context => _context?.Name;
|
||||
public int Priority => _priority;
|
||||
public string Prefix => _prefix;
|
||||
internal Texture2D Image => _image;
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(ImagePage))]
|
||||
public class ImageDisplayScriptableObjectEditor : Editor
|
||||
{
|
||||
private ImagePage _imageDisplay;
|
||||
private ImageView _imageView;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_imageDisplay = (ImagePage)target;
|
||||
_imageView = new ImageView(this);
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
if (_imageDisplay.Image)
|
||||
{
|
||||
_imageView.Draw(_imageDisplay.Image);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Draw the default properties
|
||||
base.OnInspectorGUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a249c5c9df69431f935e9e49b478eab4
|
||||
timeCreated: 1680673274
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 598c7a56ab9a46c7919d1cae7c0bfbc2
|
||||
timeCreated: 1683064505
|
||||
@ -0,0 +1,317 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine.SceneManagement;
|
||||
using Sample = Meta.Voice.Hub.Content.Sample;
|
||||
using PackageInfo = UnityEditor.PackageManager.PackageInfo;
|
||||
using PackageSample = UnityEditor.PackageManager.UI.Sample;
|
||||
|
||||
namespace Meta.Voice.Hub.Inspectors
|
||||
{
|
||||
[CustomEditor(typeof(Sample))]
|
||||
public class SampleEditor : Editor
|
||||
{
|
||||
#if VSDK_INTERNAL
|
||||
private bool edit = true;
|
||||
#else
|
||||
private bool edit = false;
|
||||
#endif
|
||||
private Sample _sample;
|
||||
|
||||
// Layout
|
||||
private const float _sampleMargin = 5f;
|
||||
private const float _sampleButtonHeight = 30f;
|
||||
private const float _sampleIconMaxWidth = 540f;
|
||||
private static GUIStyle _sampleTitleStyle;
|
||||
private static GUIStyle _sampleWordwrapStyle;
|
||||
private static GUIStyle _sampleSizeStyle;
|
||||
|
||||
// Text
|
||||
private const string _textOpenSample = "Open Sample";
|
||||
private const string _textImportSample = "Import Sample";
|
||||
private const string _textInsideSample = "Currently Open";
|
||||
private const string _textMissingSample = "Sample Not Found";
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_sample = (Sample) target;
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
DrawSample(_sample, EditorGUIUtility.currentViewWidth - 40f, true);
|
||||
|
||||
#if VSDK_INTERNAL
|
||||
GUILayout.Space(16);
|
||||
edit = EditorGUILayout.Foldout(edit, "Edit");
|
||||
#endif
|
||||
|
||||
if (edit)
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw method for a sample
|
||||
/// </summary>
|
||||
/// <param name="sample">Sample to be drawn</param>
|
||||
/// <param name="tileSize">Width of a tile</param>
|
||||
public static void DrawSample(Sample sample, float tileSize, bool showDescription = false)
|
||||
{
|
||||
// Generate all required styles
|
||||
InitStyles();
|
||||
|
||||
// Begin
|
||||
GUILayout.BeginVertical(EditorStyles.helpBox, GUILayout.Width(tileSize));
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(_sampleMargin);
|
||||
GUILayout.BeginVertical();
|
||||
|
||||
// Image
|
||||
if (sample.tileImage != null)
|
||||
{
|
||||
float imageWidth = tileSize - _sampleMargin * 2f;
|
||||
imageWidth = Mathf.Min(imageWidth, sample.tileImage.width, _sampleIconMaxWidth);
|
||||
float imageHeight = imageWidth * sample.tileImage.height / sample.tileImage.width;
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.Label(sample.tileImage, GUILayout.Width(imageWidth), GUILayout.Height(imageHeight));
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
// Title
|
||||
GUILayout.Label(sample.title, _sampleTitleStyle, GUILayout.Height(_sampleTitleStyle.lineHeight * 2));
|
||||
GUILayout.Space(_sampleMargin);
|
||||
|
||||
// Description if applicable
|
||||
if (showDescription)
|
||||
{
|
||||
GUILayout.Label(sample.description, _sampleWordwrapStyle);
|
||||
GUILayout.Space(_sampleMargin);
|
||||
}
|
||||
|
||||
// Open/Import button
|
||||
DrawOpenSampleButton(sample);
|
||||
GUILayout.Space(_sampleMargin);
|
||||
|
||||
// Complete
|
||||
GUILayout.EndVertical();
|
||||
GUILayout.Space(_sampleMargin);
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
// Draw button for open sample
|
||||
public static void DrawOpenSampleButton(Sample sample)
|
||||
{
|
||||
// Get sample package if possible
|
||||
PackageSample packagedSample = GetPackageSample(sample);
|
||||
|
||||
// Already opened
|
||||
if (IsSampleOpened(sample))
|
||||
{
|
||||
bool defaultEnabled = GUI.enabled;
|
||||
GUI.enabled = false;
|
||||
GUILayout.Button(_textInsideSample, GUILayout.Height(_sampleButtonHeight));
|
||||
GUI.enabled = defaultEnabled;
|
||||
}
|
||||
// Open
|
||||
else if (CanOpenSample(sample, packagedSample))
|
||||
{
|
||||
// Show open button
|
||||
if (GUILayout.Button(_textOpenSample, GUILayout.Height(_sampleButtonHeight)))
|
||||
{
|
||||
OpenSample(sample, packagedSample);
|
||||
}
|
||||
}
|
||||
// Import
|
||||
else if (IsPackageSampleValid(packagedSample) && !packagedSample.isImported)
|
||||
{
|
||||
// Show import button
|
||||
GUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button(_textImportSample, GUILayout.Height(_sampleButtonHeight)))
|
||||
{
|
||||
ImportSample(packagedSample);
|
||||
}
|
||||
// Show import size
|
||||
GUIContent sizeContent = new GUIContent(GetSampleSize(packagedSample));
|
||||
float sizeWidth = _sampleSizeStyle.CalcSize(sizeContent).x;
|
||||
GUILayout.Label(sizeContent, _sampleSizeStyle, GUILayout.Width(sizeWidth), GUILayout.Height(_sampleButtonHeight));
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
// Error log
|
||||
else
|
||||
{
|
||||
Color defaultColor = GUI.color;
|
||||
bool defaultEnabled = GUI.enabled;
|
||||
GUI.color = Color.red;
|
||||
GUI.enabled = false;
|
||||
GUILayout.Button(_textMissingSample, GUILayout.Height(_sampleButtonHeight));
|
||||
GUI.color = defaultColor;
|
||||
GUI.enabled = defaultEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
private static void InitStyles()
|
||||
{
|
||||
if (null == _sampleTitleStyle)
|
||||
{
|
||||
_sampleTitleStyle = new GUIStyle(EditorStyles.boldLabel);
|
||||
_sampleTitleStyle.wordWrap = true;
|
||||
_sampleTitleStyle.fontSize = 16;
|
||||
_sampleTitleStyle.alignment = TextAnchor.UpperLeft;
|
||||
}
|
||||
|
||||
if (null == _sampleWordwrapStyle)
|
||||
{
|
||||
_sampleWordwrapStyle = new GUIStyle(EditorStyles.label);
|
||||
_sampleWordwrapStyle.wordWrap = true;
|
||||
}
|
||||
|
||||
if (null == _sampleSizeStyle)
|
||||
{
|
||||
_sampleSizeStyle = new GUIStyle(EditorStyles.label);
|
||||
_sampleSizeStyle.alignment = TextAnchor.MiddleRight;
|
||||
_sampleSizeStyle.fontSize = 12;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a sample is currently opened
|
||||
/// </summary>
|
||||
/// <param name="sample">The sample asset data referencing the sample scene.</param>
|
||||
public static bool IsSampleOpened(Sample sample)
|
||||
{
|
||||
if (sample.sceneReference != null)
|
||||
{
|
||||
for (int i = 0; i < SceneManager.sceneCount; i++)
|
||||
{
|
||||
Scene scene = SceneManager.GetSceneAt(i);
|
||||
if (scene.isLoaded && string.Equals(sample.sceneReference.name, scene.name))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a sample can be opened, if false the sample must be imported.
|
||||
/// </summary>
|
||||
/// <param name="sample">The sample data to be checked</param>
|
||||
/// <returns>True if sample is imported & can be opened</returns>
|
||||
public static bool CanOpenSample(Sample sample) => CanOpenSample(sample, GetPackageSample(sample));
|
||||
// Checks if sample scene reference can be opened or if a packaged sample is imported
|
||||
private static bool CanOpenSample(Sample sample, PackageSample packagedSample)
|
||||
{
|
||||
return sample.sceneReference != null || (IsPackageSampleValid(packagedSample) && packagedSample.isImported);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a sample if possible
|
||||
/// </summary>
|
||||
/// <param name="sample">The sample data asset to be opened</param>
|
||||
public static void OpenSample(Sample sample) => OpenSample(sample, GetPackageSample(sample));
|
||||
// Opens a sample scene if found, otherwise attempts to find and open sample scene in package
|
||||
private static void OpenSample(Sample sample, PackageSample packagedSample)
|
||||
{
|
||||
// Open via sample reference
|
||||
if (sample.sceneReference != null)
|
||||
{
|
||||
string scenePath = AssetDatabase.GetAssetPath(sample.sceneReference);
|
||||
EditorSceneManager.OpenScene(scenePath);
|
||||
return;
|
||||
}
|
||||
// Failure
|
||||
Debug.LogError($"HUB Sample - Cannot Open Sample\nSample: {sample.title}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imports a sample into the current scene
|
||||
/// </summary>
|
||||
public static void ImportSample(PackageSample sample)
|
||||
{
|
||||
if (!sample.isImported)
|
||||
{
|
||||
sample.Import(PackageSample.ImportOptions.OverridePreviousImports);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns package sample data struct if specified sample name matches the asset's package name & version
|
||||
private static PackageSample GetPackageSample(Sample sample)
|
||||
{
|
||||
string sampleAssetPath = AssetDatabase.GetAssetPath(sample);
|
||||
PackageInfo info = PackageInfo.FindForAssetPath(sampleAssetPath);
|
||||
if (info != null && !string.IsNullOrEmpty(info.packageId))
|
||||
{
|
||||
foreach (var packageSample in PackageSample.FindByPackage(info.name, info.version))
|
||||
{
|
||||
if (string.Equals(packageSample.displayName, sample.packageSampleName))
|
||||
{
|
||||
return packageSample;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new PackageSample();
|
||||
}
|
||||
// Returns true if the package sample struct is not empty
|
||||
private static bool IsPackageSampleValid(PackageSample packagedSample)
|
||||
{
|
||||
return !string.IsNullOrEmpty(packagedSample.displayName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine size of a sample
|
||||
/// </summary>
|
||||
/// <param name="sample">The sample data asset to be opened</param>
|
||||
public static void GetSampleSize(Sample sample) => GetSampleSize(GetPackageSample(sample));
|
||||
// Gets sample size from from packaged sample
|
||||
private static string GetSampleSize(PackageSample sample)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sample.resolvedPath) || !Directory.Exists(sample.resolvedPath))
|
||||
return "0 KB";
|
||||
return ConvertToString(GetDirectorySize(sample.resolvedPath));
|
||||
}
|
||||
private static ulong GetDirectorySize(string directory)
|
||||
{
|
||||
ulong sizeInBytes = 0;
|
||||
foreach (string fileName in Directory.GetFiles(directory, "*.*", SearchOption.AllDirectories))
|
||||
{
|
||||
FileInfo fileInfo = new FileInfo(fileName);
|
||||
sizeInBytes += (ulong) fileInfo.Length;
|
||||
}
|
||||
return sizeInBytes;
|
||||
}
|
||||
private static string ConvertToString(ulong sizeInBytes)
|
||||
{
|
||||
double size = sizeInBytes / _sizeUnitMax;
|
||||
int index = 0;
|
||||
while (size >= _sizeUnitMax && index < _sizeUnits.Length - 1)
|
||||
{
|
||||
++index;
|
||||
size /= _sizeUnitMax;
|
||||
}
|
||||
return $"{size:0.##} {_sizeUnits[index]}";
|
||||
}
|
||||
private const double _sizeUnitMax = 1024.0;
|
||||
private static readonly string[] _sizeUnits = new string[4]
|
||||
{
|
||||
"KB",
|
||||
"MB",
|
||||
"GB",
|
||||
"TB"
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a932bbf699694d1b849d6375d1f3452b
|
||||
timeCreated: 1683064516
|
||||
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Meta.Voice.Hub.Content;
|
||||
using Meta.Voice.Hub.Interfaces;
|
||||
using Meta.Voice.Hub.Utilities;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Meta.Voice.Hub.Inspectors
|
||||
{
|
||||
[CustomEditor(typeof(SamplesPage))]
|
||||
public class SamplesPageInspector : Editor, IOverrideSize
|
||||
{
|
||||
#if VSDK_INTERNAL
|
||||
private bool edit = true;
|
||||
#else
|
||||
private bool edit = false;
|
||||
#endif
|
||||
|
||||
const float _tileSize = 200;
|
||||
|
||||
private List<Sample> _samples = new List<Sample>();
|
||||
private SamplesPage _samplePage;
|
||||
public float OverrideWidth { get; set; } = -1;
|
||||
public float OverrideHeight { get; set; } = -1;
|
||||
|
||||
private Vector2 _scrollOffset;
|
||||
private float _minTileMargin = 15f;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_samples.Clear();
|
||||
_samplePage = (SamplesPage) target;
|
||||
var samples = PageFinder.FindPages(typeof(Sample));
|
||||
|
||||
foreach (var so in samples)
|
||||
{
|
||||
var sample = (Sample)so;
|
||||
if (sample.sampleSetId == _samplePage.SampleSetId)
|
||||
{
|
||||
_samples.Add(sample);
|
||||
}
|
||||
}
|
||||
|
||||
_samples.Sort((a, b) =>
|
||||
{
|
||||
int cmp = a.priority.CompareTo(b.priority);
|
||||
if (cmp == 0) cmp = a.name.CompareTo(b.name);
|
||||
return cmp;
|
||||
});
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
_scrollOffset = GUILayout.BeginScrollView(_scrollOffset);
|
||||
var windowWidth = (OverrideWidth > 0 ? OverrideWidth : EditorGUIUtility.currentViewWidth) - _minTileMargin;
|
||||
var columns = (int) (windowWidth / (_tileSize + _minTileMargin));
|
||||
int col = 0;
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
for (int i = 0; i < _samples.Count; i++)
|
||||
{
|
||||
if (col >= columns)
|
||||
{
|
||||
col = 0;
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
}
|
||||
|
||||
var sample = _samples[i];
|
||||
SampleEditor.DrawSample(sample, _tileSize);
|
||||
GUILayout.FlexibleSpace();
|
||||
col++;
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
#if VSDK_INTERNAL
|
||||
GUILayout.Space(16);
|
||||
edit = EditorGUILayout.Foldout(edit, "Edit");
|
||||
#endif
|
||||
if (edit)
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
}
|
||||
GUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
public static void OpenSceneFromGUID(string scenePath)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(scenePath))
|
||||
{
|
||||
SceneAsset sceneAsset = AssetDatabase.LoadAssetAtPath<SceneAsset>(scenePath);
|
||||
if (sceneAsset != null)
|
||||
{
|
||||
if (EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
|
||||
{
|
||||
EditorSceneManager.OpenScene(scenePath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"Scene asset not found at path: {scenePath}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"Scene not found {scenePath}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d28e3c645082479ea5149b09828c745c
|
||||
timeCreated: 1683067820
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d6e8cb15dbf44a0b9fb35536ecd9d5f
|
||||
timeCreated: 1680898102
|
||||
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
namespace Meta.Voice.Hub.Interfaces
|
||||
{
|
||||
public interface IOverrideSize
|
||||
{
|
||||
float OverrideWidth { get; set; }
|
||||
float OverrideHeight { get; set; }
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ab13218e15145a792b14452a94dcf16
|
||||
timeCreated: 1680898110
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 61bdbee982945e342b8e4e3766304221
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using System.Text.RegularExpressions;
|
||||
using Meta.Voice.Hub.Interfaces;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
namespace Meta.Voice.Hub.Markdown
|
||||
{
|
||||
[CustomEditor(typeof(MarkdownPage))]
|
||||
public class MarkdownInspector : Editor, IOverrideSize
|
||||
{
|
||||
private GUIStyle _linkStyle;
|
||||
private GUIStyle _normalTextStyle;
|
||||
private GUIStyle _imageLabelStyle;
|
||||
private Dictionary<string, Texture2D> _cachedImages = new Dictionary<string, Texture2D>();
|
||||
private Texture2D _badImageTex;
|
||||
|
||||
private Vector2 scrollView;
|
||||
|
||||
public float OverrideWidth { get; set; } = -1;
|
||||
public float OverrideHeight { get; set; } = -1;
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
float padding = 55;
|
||||
var markdownPage = ((MarkdownPage)target);
|
||||
if (!markdownPage)
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
return;
|
||||
}
|
||||
|
||||
var markdownFile = markdownPage.MarkdownFile;
|
||||
if (!markdownFile)
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
return;
|
||||
}
|
||||
|
||||
var text = markdownFile.text;
|
||||
|
||||
if (_linkStyle == null)
|
||||
{
|
||||
_linkStyle = new GUIStyle(GUI.skin.label)
|
||||
{
|
||||
richText = true,
|
||||
wordWrap = true,
|
||||
alignment = TextAnchor.MiddleLeft
|
||||
};
|
||||
}
|
||||
|
||||
if (_normalTextStyle == null)
|
||||
{
|
||||
_normalTextStyle = new GUIStyle(GUI.skin.label)
|
||||
{
|
||||
wordWrap = true,
|
||||
richText = true,
|
||||
alignment = TextAnchor.MiddleLeft
|
||||
};
|
||||
}
|
||||
|
||||
Event currentEvent = Event.current;
|
||||
Regex urlRegex = new Regex(@"(https?://[^\s]+)");
|
||||
Regex imageRegex = new Regex(@"!\[(.*?)\]\((.*?)\)");
|
||||
Regex splitRegex = new Regex(@"(!\[.*?\]\(.*?\))|(https?://[^\s]+)");
|
||||
string[] parts = splitRegex.Split(text);
|
||||
|
||||
scrollView = GUILayout.BeginScrollView(scrollView);
|
||||
var windowWidth = (OverrideWidth > 0 ? OverrideWidth : EditorGUIUtility.currentViewWidth) - padding;
|
||||
GUILayout.BeginVertical(GUILayout.Width(windowWidth));
|
||||
foreach (string part in parts)
|
||||
{
|
||||
if (imageRegex.IsMatch(part))
|
||||
{
|
||||
Match imageMatch = imageRegex.Match(part);
|
||||
|
||||
if (imageMatch.Success)
|
||||
{
|
||||
string imagePath = imageMatch.Groups[2].Value;
|
||||
|
||||
if (!_cachedImages.ContainsKey(imagePath))
|
||||
{
|
||||
if (urlRegex.IsMatch(imagePath))
|
||||
{
|
||||
LoadImageFromUrl(imagePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
var path = AssetDatabase.GetAssetPath(markdownPage);
|
||||
var dir = Path.GetDirectoryName(path);
|
||||
Texture2D image = AssetDatabase.LoadAssetAtPath<Texture2D>(dir + "/" + imagePath);
|
||||
if (!image)
|
||||
{
|
||||
// Get the path of target markdown file
|
||||
string markdownPath = AssetDatabase.GetAssetPath(markdownFile);
|
||||
// Get the directory of the markdown file
|
||||
string markdownDir = System.IO.Path.GetDirectoryName(markdownPath);
|
||||
image = AssetDatabase.LoadAssetAtPath<Texture2D>(Path.Combine(markdownDir,
|
||||
imagePath));
|
||||
if (!image) image = _badImageTex;
|
||||
}
|
||||
|
||||
_cachedImages[imagePath] = image;
|
||||
}
|
||||
}
|
||||
|
||||
if (_cachedImages.TryGetValue(imagePath, out Texture2D img) && img && img != _badImageTex)
|
||||
{
|
||||
float aspectRatio = 1;
|
||||
float width = img.width;
|
||||
float height = img.height;
|
||||
if (img.width > windowWidth - padding)
|
||||
{
|
||||
width = windowWidth - padding;
|
||||
aspectRatio = img.width / (float) img.height;
|
||||
height = width / aspectRatio;
|
||||
}
|
||||
|
||||
if (null == _imageLabelStyle)
|
||||
{
|
||||
_imageLabelStyle = new GUIStyle(GUI.skin.label)
|
||||
{
|
||||
alignment = TextAnchor.MiddleCenter,
|
||||
imagePosition = ImagePosition.ImageAbove
|
||||
};
|
||||
}
|
||||
|
||||
GUIContent content = new GUIContent(img);
|
||||
Rect imageLabelRect = GUILayoutUtility.GetRect(content, _imageLabelStyle,
|
||||
GUILayout.Height(height), GUILayout.Width(width));
|
||||
|
||||
if (GUI.Button(imageLabelRect, content, _imageLabelStyle))
|
||||
{
|
||||
ImageViewer.ShowWindow(img, Path.GetFileNameWithoutExtension(imagePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (urlRegex.IsMatch(part))
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
GUILayout.Space(EditorGUI.indentLevel * 15);
|
||||
GUILayout.Label("<color=blue>" + part + "</color>", _linkStyle, GUILayout.MaxWidth(windowWidth));
|
||||
|
||||
Rect linkRect = GUILayoutUtility.GetLastRect();
|
||||
if (currentEvent.type == EventType.MouseDown && linkRect.Contains(currentEvent.mousePosition))
|
||||
{
|
||||
Application.OpenURL(part);
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField(ParseMarkdown(part), _normalTextStyle, GUILayout.MaxWidth(windowWidth));
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
GUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
public static string ParseMarkdown(string markdown)
|
||||
{
|
||||
// Headers
|
||||
markdown = Regex.Replace(markdown, @"^######\s(.*?)$", "<size=14><b>$1</b></size>", RegexOptions.Multiline);
|
||||
markdown = Regex.Replace(markdown, @"^#####\s(.*?)$", "<size=16><b>$1</b></size>", RegexOptions.Multiline);
|
||||
markdown = Regex.Replace(markdown, @"^####\s(.*?)$", "<size=18><b>$1</b></size>", RegexOptions.Multiline);
|
||||
markdown = Regex.Replace(markdown, @"^###\s(.*?)$", "<size=20><b>$1</b></size>", RegexOptions.Multiline);
|
||||
markdown = Regex.Replace(markdown, @"^##\s(.*?)$", "<size=22><b>$1</b></size>", RegexOptions.Multiline);
|
||||
markdown = Regex.Replace(markdown, @"^#\s(.*?)$", "<size=24><b>$1</b></size>", RegexOptions.Multiline);
|
||||
|
||||
// Bold
|
||||
markdown = Regex.Replace(markdown, @"\*\*(.*?)\*\*", "<b>$1</b>", RegexOptions.Multiline);
|
||||
|
||||
// Italic
|
||||
markdown = Regex.Replace(markdown, @"\*(.*?)\*", "<i>$1</i>", RegexOptions.Multiline);
|
||||
|
||||
// Code blocks
|
||||
markdown = Regex.Replace(markdown, @"(?s)```(.*?)```", m =>
|
||||
{
|
||||
var codeLines = m.Groups[1].Value.Trim().Split('\n');
|
||||
string result = string.Empty;
|
||||
foreach (var line in codeLines)
|
||||
{
|
||||
result += $" <color=#a1b56c>{line}</color>\n";
|
||||
}
|
||||
|
||||
return result;
|
||||
}, RegexOptions.Multiline);
|
||||
|
||||
// Raw Urls
|
||||
markdown = Regex.Replace(markdown, @"(https?:\/\/[^\s""'<>]+)",
|
||||
"<link><color=#a1b56c><u>$1</u></color></link>", RegexOptions.Multiline);
|
||||
|
||||
// Unordered lists
|
||||
markdown = Regex.Replace(markdown, @"^\s*\*\s(.*?)$", "• $1", RegexOptions.Multiline);
|
||||
|
||||
// Ordered lists
|
||||
markdown = Regex.Replace(markdown, @"^(\d+)\.\s(.*?)$", "$1. $2", RegexOptions.Multiline);
|
||||
|
||||
return markdown;
|
||||
}
|
||||
|
||||
private void LoadImageFromUrl(string url)
|
||||
{
|
||||
_cachedImages[url] = _badImageTex;
|
||||
UnityWebRequest request = UnityWebRequestTexture.GetTexture(url);
|
||||
request.SendWebRequest().completed += operation =>
|
||||
{
|
||||
if (request.responseCode == 200)
|
||||
{
|
||||
Texture2D texture = DownloadHandlerTexture.GetContent(request);
|
||||
_cachedImages[url] = texture;
|
||||
Repaint();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"Failed to load image from URL [Error {request.responseCode}]: {url}");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e1014ec949564436944663d476cf2c48
|
||||
timeCreated: 1680838351
|
||||
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using Meta.Voice.Hub;
|
||||
using Meta.Voice.Hub.Attributes;
|
||||
using Meta.Voice.Hub.Interfaces;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Meta.Voice.Hub.Markdown
|
||||
{
|
||||
[MetaHubPageScriptableObject]
|
||||
public class MarkdownPage : ScriptableObject, IPageInfo
|
||||
{
|
||||
[SerializeField] private string _displayName;
|
||||
[SerializeField] private string _prefix;
|
||||
[SerializeField] private MetaHubContext _context;
|
||||
[SerializeField] private TextAsset _markdownFile;
|
||||
[SerializeField] private int _priority = 0;
|
||||
|
||||
internal TextAsset MarkdownFile => _markdownFile;
|
||||
public string Name => _displayName ?? name;
|
||||
public string Context => _context.Name;
|
||||
public int Priority => _priority;
|
||||
public string Prefix => _prefix;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 98bfdca232b84c3db2527e4b5c9d3b9d
|
||||
timeCreated: 1680839218
|
||||
@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "Meta.Voice.Hub.Editor",
|
||||
"rootNamespace": "Meta.Voice.Hub",
|
||||
"references": [
|
||||
"GUID:8e054d88729a3fb4bbe539499f824363",
|
||||
"GUID:4c3436cc699cb25459568e9fa95b7fd7"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4f6d7d3afe393a4c8034af2ef0f36a8
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
606
Assets/Oculus/Voice/Features/Hub/Scripts/Editor/MetaHub.cs
Normal file
606
Assets/Oculus/Voice/Features/Hub/Scripts/Editor/MetaHub.cs
Normal file
@ -0,0 +1,606 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Meta.Voice.Hub.Attributes;
|
||||
using Meta.Voice.Hub.Interfaces;
|
||||
using Meta.Voice.Hub.UIComponents;
|
||||
using Meta.Voice.Hub.Utilities;
|
||||
using Meta.Voice.TelemetryUtilities;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Meta.Voice.Hub
|
||||
{
|
||||
public class MetaHub : EditorWindow
|
||||
{
|
||||
[SerializeField] private Texture2D _icon;
|
||||
[SerializeField] private Texture2D _logoImage;
|
||||
|
||||
private int _leftPanelWidth = 200;
|
||||
|
||||
private List<MetaHubContext> _contexts = new List<MetaHubContext>();
|
||||
private Dictionary<string, MetaHubContext> _contextMap = new Dictionary<string, MetaHubContext>();
|
||||
|
||||
private List<PageGroup> _pageGroups = new List<PageGroup>();
|
||||
private Dictionary<MetaHubContext, PageGroup> _pageGroupMap = new Dictionary<MetaHubContext, PageGroup>();
|
||||
|
||||
public MetaHubContext PrimaryContext
|
||||
{
|
||||
get
|
||||
{
|
||||
if (ContextFilter.Count > 0)
|
||||
{
|
||||
var filter = ContextFilter.First();
|
||||
if (_contextMap.TryGetValue(filter, out var context))
|
||||
{
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return _contexts[0];
|
||||
}
|
||||
}
|
||||
|
||||
public GUIContent TitleContent => new GUIContent(PrimaryContext.Title, PrimaryContext.Icon);
|
||||
public Texture2D LogoImage => PrimaryContext.LogoImage ? PrimaryContext.LogoImage : _logoImage;
|
||||
|
||||
public const string DEFAULT_CONTEXT = "";
|
||||
|
||||
public virtual List<string> ContextFilter => new List<string>();
|
||||
|
||||
private string _selectedPageId;
|
||||
|
||||
public string SelectedPage
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == _selectedPageId)
|
||||
{
|
||||
_selectedPageId = SessionState.GetString(SessionKeySelPage, null);
|
||||
}
|
||||
|
||||
return _selectedPageId;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_selectedPageId != value)
|
||||
{
|
||||
_selectedPageId = value;
|
||||
Telemetry.LogInstantEvent(Telemetry.TelemetryEventId.OpenUi,
|
||||
new Dictionary<Telemetry.AnnotationKey, string>()
|
||||
{
|
||||
{ Telemetry.AnnotationKey.PageId, _selectedPageId }
|
||||
});
|
||||
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
SessionState.SetString(SessionKeySelPage, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string SessionKeySelPage => GetType().Namespace + "." + GetType().Name + "::SelectedPage";
|
||||
|
||||
private PageGroup _rootPageGroup;
|
||||
|
||||
private class PageGroup
|
||||
{
|
||||
private MetaHubContext _context;
|
||||
private List<PageReference> _pages = new List<PageReference>();
|
||||
private HashSet<string> _addedPages = new HashSet<string>();
|
||||
private FoldoutHierarchy<PageReference> _foldoutHierarchy = new FoldoutHierarchy<PageReference>();
|
||||
private readonly Action<PageReference> _onDrawPage;
|
||||
|
||||
public MetaHubContext Context => _context;
|
||||
public IEnumerable<PageReference> Pages => _pages;
|
||||
public int PageCount => _pages.Count;
|
||||
public FoldoutHierarchy<PageReference> Hierarchy => _foldoutHierarchy;
|
||||
|
||||
public PageGroup(MetaHubContext context, Action<PageReference> onDrawPage)
|
||||
{
|
||||
_context = context;
|
||||
_onDrawPage = onDrawPage;
|
||||
}
|
||||
|
||||
public void AddPage(PageReference page)
|
||||
{
|
||||
var pageId = page.PageId;
|
||||
if (!_addedPages.Contains(pageId))
|
||||
{
|
||||
_addedPages.Add(pageId);
|
||||
_pages.Add(page);
|
||||
var prefix = page.info.Prefix?.Trim(new char[] { '/' });
|
||||
if (prefix.Length > 0)
|
||||
{
|
||||
prefix += "/";
|
||||
}
|
||||
var path = "/" + prefix + page.info.Name;
|
||||
_foldoutHierarchy.Add(path, new FoldoutHierarchyItem<PageReference> {
|
||||
path = path,
|
||||
item = page,
|
||||
onDraw = _onDrawPage
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void Sort()
|
||||
{
|
||||
Sort(_pages);
|
||||
}
|
||||
|
||||
public void Sort(List<PageReference> pages)
|
||||
{
|
||||
pages.Sort((a, b) =>
|
||||
{
|
||||
int compare = a.info.Priority.CompareTo(b.info.Priority);
|
||||
if (compare == 0) compare = string.Compare(a.info.Name, b.info.Name);
|
||||
return compare;
|
||||
});
|
||||
_foldoutHierarchy = new FoldoutHierarchy<PageReference>();
|
||||
foreach (var page in _pages)
|
||||
{
|
||||
var path = "/" + page.info.Prefix + page.info.Name;
|
||||
_foldoutHierarchy.Add(path, new FoldoutHierarchyItem<PageReference> {
|
||||
path = path,
|
||||
item = page,
|
||||
onDraw = _onDrawPage
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct PageReference
|
||||
{
|
||||
public IMetaHubPage page;
|
||||
public IPageInfo info;
|
||||
public string PageId => info.Context + "::" + info.Name;
|
||||
}
|
||||
|
||||
private string _searchString = "";
|
||||
private IMetaHubPage _selectedPage;
|
||||
private Vector2 _scroll;
|
||||
private Vector2 _leftScroll;
|
||||
|
||||
private IMetaHubPage ActivePage
|
||||
{
|
||||
get => _selectedPage;
|
||||
set
|
||||
{
|
||||
if (_selectedPage != value)
|
||||
{
|
||||
if (null != _selectedPage)
|
||||
{
|
||||
DisableSelectedPage(_selectedPage);
|
||||
}
|
||||
_selectedPage = value;
|
||||
EnableSelectedPage(_selectedPage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void InvokeLifecyle(IMetaHubPage page, string lifecycleMethod)
|
||||
{
|
||||
if (null == page) return;
|
||||
|
||||
var method = page.GetType()
|
||||
.GetMethod(lifecycleMethod, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
||||
method?.Invoke(page, new object[0]);
|
||||
}
|
||||
|
||||
|
||||
private void DisableSelectedPage(IMetaHubPage page)
|
||||
{
|
||||
InvokeLifecyle(page, "OnDisable");
|
||||
}
|
||||
|
||||
private void EnableSelectedPage(IMetaHubPage page)
|
||||
{
|
||||
if (null == page) return;
|
||||
|
||||
var method = page.GetType()
|
||||
.GetMethod("OnWindow", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
||||
method?.Invoke(page, new object[] {this});
|
||||
InvokeLifecyle(page, "OnEnable");
|
||||
}
|
||||
|
||||
private void OnSelectionChange()
|
||||
{
|
||||
InvokeLifecyle(ActivePage, "OnSelectionChange");
|
||||
}
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
UpdateContextFilter();
|
||||
|
||||
minSize = new Vector2(400, 400);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (null != _selectedPage)
|
||||
{
|
||||
ActivePage = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void AddChildContexts(List<string> filter)
|
||||
{
|
||||
var parents = new HashSet<string>();
|
||||
foreach (var parent in filter)
|
||||
{
|
||||
parents.Add(parent);
|
||||
}
|
||||
var contexts = ContextFinder.FindAllContextAssets<MetaHubContext>();
|
||||
foreach (var context in contexts)
|
||||
{
|
||||
if (!context) continue;
|
||||
if (null == context.ParentContexts) continue;
|
||||
|
||||
foreach (var parentContext in context.ParentContexts)
|
||||
{
|
||||
if(parents.Contains(parentContext)) filter.Add(context.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateContextFilter()
|
||||
{
|
||||
if(null == _rootPageGroup) _rootPageGroup = new PageGroup(null, DrawPageEntry);
|
||||
_contexts = ContextFinder.FindAllContextAssets<MetaHubContext>();
|
||||
_contexts.Sort((a, b) => a.Priority.CompareTo(b.Priority));
|
||||
foreach (var context in _contexts)
|
||||
{
|
||||
_contextMap[context.Name] = context;
|
||||
var pageGroup = new PageGroup(context, DrawPageEntry);
|
||||
if (!_pageGroupMap.ContainsKey(context))
|
||||
{
|
||||
_pageGroups.Add(pageGroup);
|
||||
_pageGroupMap[context] = pageGroup;
|
||||
|
||||
foreach (var soPage in context.ScriptableObjectReflectionPages)
|
||||
{
|
||||
var pages = PageFinder.FindPages(soPage.scriptableObjectType);
|
||||
foreach (var so in pages)
|
||||
{
|
||||
var page = new ScriptableObjectPage(so, context.Name, prefix: soPage.namePrefix, priority: soPage.priorityModifier);
|
||||
AddPage(new PageReference
|
||||
{
|
||||
page = page,
|
||||
info = page
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var page in ContextFinder.FindAllContextAssets<MetaHubPage>())
|
||||
{
|
||||
AddPage(new PageReference
|
||||
{
|
||||
page = page,
|
||||
info = page
|
||||
});
|
||||
}
|
||||
|
||||
foreach (var pageType in PageFinder.FindPages())
|
||||
{
|
||||
var pageInfo = PageFinder.GetPageInfo(pageType);
|
||||
|
||||
if (pageInfo is MetaHubPageScriptableObjectAttribute)
|
||||
{
|
||||
var pages = PageFinder.FindPages(pageType);
|
||||
foreach (var page in pages)
|
||||
{
|
||||
var soPage = new ScriptableObjectPage(page, pageInfo);
|
||||
AddPage(new PageReference
|
||||
{
|
||||
page = soPage,
|
||||
info = soPage
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
IMetaHubPage page;
|
||||
if (pageType.IsSubclassOf(typeof(ScriptableObject)))
|
||||
{
|
||||
page = (IMetaHubPage) ScriptableObject.CreateInstance(pageType);
|
||||
}
|
||||
else
|
||||
{
|
||||
page = Activator.CreateInstance(pageType) as IMetaHubPage;
|
||||
}
|
||||
if(page is IPageInfo info) AddPage(new PageReference { page = page, info = info});
|
||||
else AddPage(new PageReference { page = page, info = pageInfo});
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the pages by priority then alpha
|
||||
foreach (var group in _pageGroupMap.Values)
|
||||
{
|
||||
group.Sort();
|
||||
}
|
||||
}
|
||||
|
||||
private void AddPage(PageReference page)
|
||||
{
|
||||
if (string.IsNullOrEmpty(page.info.Context)) _rootPageGroup.AddPage(page);
|
||||
else if (_contextMap.TryGetValue(page.info.Context, out var groupKey)
|
||||
&& _pageGroupMap.TryGetValue(groupKey, out var group))
|
||||
{
|
||||
group.AddPage(page);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnGUI()
|
||||
{
|
||||
titleContent = TitleContent;
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
_searchString = EditorGUILayout.TextField(_searchString, EditorStyles.toolbarSearchField);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
DrawLeftPanel();
|
||||
DrawRightPanel();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
private void DrawLeftPanel()
|
||||
{
|
||||
EditorGUILayout.BeginVertical(GUILayout.Width(_leftPanelWidth));
|
||||
|
||||
var logo = LogoImage;
|
||||
// Draw logo image
|
||||
if (logo)
|
||||
{
|
||||
float aspectRatio = logo.width / (float) logo.height;
|
||||
GUILayout.Box(logo, GUILayout.Width(_leftPanelWidth), GUILayout.Height(_leftPanelWidth / aspectRatio));
|
||||
}
|
||||
|
||||
_leftScroll = GUILayout.BeginScrollView(_leftScroll);
|
||||
DrawPageGroup(_rootPageGroup);
|
||||
foreach (var context in _pageGroups)
|
||||
{
|
||||
DrawPageGroup(context);
|
||||
}
|
||||
GUILayout.EndScrollView();
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
private void DrawPageGroup(PageGroup group)
|
||||
{
|
||||
if (!IsGroupVisible(group)) return;
|
||||
|
||||
var searchMatchedGroupContext = ContextFilter.Count != 1 && IsGroupInSearch(group);
|
||||
|
||||
List<PageReference> pages = new List<PageReference>();
|
||||
if (!string.IsNullOrEmpty(_searchString) && !searchMatchedGroupContext)
|
||||
{
|
||||
foreach (var page in group.Pages)
|
||||
{
|
||||
if (PageInSearch(page))
|
||||
{
|
||||
pages.Add(page);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ContextFilter.Count != 1 && (string.IsNullOrEmpty(_searchString) || pages.Count > 0))
|
||||
{
|
||||
if (group.Context != PrimaryContext && null != group.Context &&
|
||||
(string.IsNullOrEmpty(_searchString) && group.PageCount > 0 || pages.Count > 0) &&
|
||||
!string.IsNullOrEmpty(group.Context.Name) && group.Context.ShowPageGroupTitle)
|
||||
{
|
||||
GUILayout.Space(8);
|
||||
GUILayout.Label(group.Context.Name, EditorStyles.boldLabel);
|
||||
}
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(_searchString))
|
||||
{
|
||||
for (int i = 0; i < pages.Count; i++)
|
||||
{
|
||||
DrawPageEntry(pages[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
group.Hierarchy.Draw();
|
||||
}
|
||||
}
|
||||
|
||||
private bool PageInSearch(PageReference page)
|
||||
{
|
||||
#if UNITY_2021_1_OR_NEWER
|
||||
return page.info.Name.Contains(_searchString, StringComparison.OrdinalIgnoreCase);
|
||||
#else
|
||||
return page.info.Name.ToLower().Contains(_searchString.ToLower());
|
||||
#endif
|
||||
}
|
||||
|
||||
private bool IsGroupInSearch(PageGroup group)
|
||||
{
|
||||
#if UNITY_2021_1_OR_NEWER
|
||||
return group.Context && group.Context.Name.Contains(_searchString,
|
||||
StringComparison.OrdinalIgnoreCase);
|
||||
#else
|
||||
return group.Context && group.Context.Name.ToLower().Contains(_searchString.ToLower());
|
||||
#endif
|
||||
}
|
||||
|
||||
private bool IsGroupVisible(PageGroup group)
|
||||
{
|
||||
return group.PageCount > 0 &&
|
||||
ContextFilter.Count == 0 && (!group.Context || group.Context.AllowWithoutContextFilter) ||
|
||||
ContextFilter.Contains(group.Context ? group.Context.Name : "");
|
||||
}
|
||||
|
||||
private void DrawPageEntry(PageReference page)
|
||||
{
|
||||
GUIStyle optionStyle = new GUIStyle(GUI.skin.label);
|
||||
optionStyle.normal.background = null;
|
||||
optionStyle.normal.textColor = _selectedPage == page.page ? Color.white : GUI.skin.label.normal.textColor;
|
||||
|
||||
if (string.IsNullOrEmpty(SelectedPage))
|
||||
{
|
||||
// TODO: We will need to improve this logic.
|
||||
if (!string.IsNullOrEmpty(SelectedPage) && page.PageId == SelectedPage) ActivePage = page.page;
|
||||
else if(string.IsNullOrEmpty(SelectedPage)) ActivePage = page.page;
|
||||
SelectedPage = page.PageId;
|
||||
}
|
||||
else if (null == ActivePage)
|
||||
{
|
||||
if (page.PageId == SelectedPage)
|
||||
{
|
||||
ActivePage = page.page;
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
{
|
||||
Rect optionRect = GUILayoutUtility.GetRect(GUIContent.none, optionStyle, GUILayout.ExpandWidth(true), GUILayout.Height(20));
|
||||
|
||||
bool isHover = optionRect.Contains(Event.current.mousePosition);
|
||||
if (isHover)
|
||||
{
|
||||
EditorGUIUtility.AddCursorRect(optionRect, MouseCursor.Link);
|
||||
}
|
||||
|
||||
Color backgroundColor;
|
||||
if (page.page == _selectedPage)
|
||||
{
|
||||
backgroundColor = EditorGUIUtility.isProSkin ? new Color(0.22f, 0.44f, 0.88f) : new Color(0.24f, 0.48f, 0.90f);
|
||||
}
|
||||
else
|
||||
{
|
||||
backgroundColor = Color.clear;
|
||||
}
|
||||
|
||||
EditorGUI.DrawRect(optionRect, backgroundColor);
|
||||
GUI.Label(optionRect, new GUIContent(page.info.Name, page.info.Name), optionStyle);
|
||||
|
||||
if (Event.current.type == EventType.MouseDown && isHover)
|
||||
{
|
||||
ActivePage = page.page;
|
||||
SelectedPage = page.PageId;
|
||||
Event.current.Use();
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
|
||||
protected virtual void DrawRightPanel()
|
||||
{
|
||||
// Create a GUIStyle with a darker background color
|
||||
GUIStyle darkBackgroundStyle = new GUIStyle();
|
||||
Texture2D backgroundTexture = new Texture2D(1, 1);
|
||||
backgroundTexture.SetPixel(0, 0, new Color(0f, 0f, 0f, .25f));
|
||||
backgroundTexture.Apply();
|
||||
darkBackgroundStyle.normal.background = backgroundTexture;
|
||||
|
||||
// Apply the dark background style to the right panel
|
||||
EditorGUILayout.BeginVertical(darkBackgroundStyle, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true));
|
||||
|
||||
if (_selectedPage is ScriptableObjectPage soPage)
|
||||
{
|
||||
if(soPage.Editor is IOverrideSize size && Event.current.type == EventType.Layout) {
|
||||
size.OverrideWidth = EditorGUIUtility.currentViewWidth - _leftPanelWidth;
|
||||
}
|
||||
}
|
||||
_selectedPage?.OnGUI();
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
public static T ShowWindow<T>(params string[] contexts) where T : MetaHub
|
||||
{
|
||||
var window = EditorWindow.GetWindow<T>();
|
||||
window.ActivePage = null;
|
||||
window.titleContent = new GUIContent("Meta Hub");
|
||||
window.UpdateContextFilter();
|
||||
window.Show();
|
||||
return window;
|
||||
}
|
||||
}
|
||||
|
||||
internal class ScriptableObjectPage : IMetaHubPage, IPageInfo
|
||||
{
|
||||
private readonly ScriptableObject _page;
|
||||
private string _context;
|
||||
private Editor _editor;
|
||||
private string _name;
|
||||
private string _prefix = "";
|
||||
private int _priority;
|
||||
|
||||
public string Name => _name;
|
||||
public string Prefix => _prefix;
|
||||
public string Context => _context;
|
||||
public Editor Editor => _editor;
|
||||
public int Priority => _priority;
|
||||
|
||||
public ScriptableObjectPage(ScriptableObject page, MetaHubPageAttribute pageInfo)
|
||||
{
|
||||
_page = page;
|
||||
_context = pageInfo.Context;
|
||||
_priority = pageInfo.Priority;
|
||||
_prefix = pageInfo.Prefix;
|
||||
|
||||
UpdatePageInfo();
|
||||
}
|
||||
|
||||
public ScriptableObjectPage(ScriptableObject page, string context, string prefix = "", int priority = 0)
|
||||
{
|
||||
_page = page;
|
||||
_context = context;
|
||||
_priority = priority;
|
||||
_prefix = prefix;
|
||||
|
||||
UpdatePageInfo();
|
||||
}
|
||||
|
||||
private void UpdatePageInfo()
|
||||
{
|
||||
if (_page is IPageInfo info)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(info.Name)) _name = info.Name;
|
||||
if (!string.IsNullOrEmpty(info.Context)) _context = info.Context;
|
||||
if (!string.IsNullOrEmpty(info.Prefix)) _prefix = info.Prefix;
|
||||
if (info.Priority != 0) _priority = info.Priority;
|
||||
}
|
||||
else
|
||||
{
|
||||
_name = _page.name;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnGUI()
|
||||
{
|
||||
if (_page)
|
||||
{
|
||||
// Create an editor for the assigned ScriptableObject
|
||||
if (_editor == null || _editor.target != _page)
|
||||
{
|
||||
_editor = Editor.CreateEditor(_page);
|
||||
}
|
||||
|
||||
// Render the ScriptableObject with its default editor
|
||||
_editor.OnInspectorGUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user