diff --git a/unity/Assets/Plugins/Emotiv-Unity-Plugin b/unity/Assets/Plugins/Emotiv-Unity-Plugin index 245f4e0..3724315 160000 --- a/unity/Assets/Plugins/Emotiv-Unity-Plugin +++ b/unity/Assets/Plugins/Emotiv-Unity-Plugin @@ -1 +1 @@ -Subproject commit 245f4e0b1a75c19fb70cc3d93846152fb1d5fb33 +Subproject commit 3724315ed5712b0dc5fe8c97dcdc85f96f796702 diff --git a/unity/Assets/SimpleExample.cs b/unity/Assets/SimpleExample.cs index 53ed419..cd594ee 100644 --- a/unity/Assets/SimpleExample.cs +++ b/unity/Assets/SimpleExample.cs @@ -5,6 +5,7 @@ using UnityEngine.UI; using System; using System.Threading.Tasks; +using Newtonsoft.Json.Linq; #if UNITY_ANDROID using UnityEngine.Android; @@ -16,6 +17,7 @@ public class SimpleExample : MonoBehaviour EmotivUnityItf _eItf = EmotivUnityItf.Instance; float _timerDataUpdate = 0; const float TIME_UPDATE_DATA = 1f; + private string _lastMessageLog = ""; // tracks last displayed _eItf.MessageLog to avoid overwriting manual MessageLog updates [SerializeField] public InputField HeadsetId; // headsetId [SerializeField] public InputField RecordTitle; // record Title @@ -36,16 +38,29 @@ public class SimpleExample : MonoBehaviour [SerializeField] public Toggle FEToggle; [SerializeField] public Toggle SYSToggle; - [SerializeField] public Text MessageLog; - - // Enable horizontal wrapping for MessageLog - private void Awake() - { - if (MessageLog != null) - { - MessageLog.horizontalOverflow = HorizontalWrapMode.Wrap; - } - } + [SerializeField] public InputField MessageLog; + // recordid for export record + [SerializeField] public InputField RecordId; // record id for export record + + // cached button references, populated once in Start() to avoid repeated GameObject.Find calls in Update() + private Button _signInBtn; + private Button _signOutBtn; + private Button _createSessionBtn; + private Button _queryHeadsetBtn; + private Button _startRecordBtn; + private Button _subscribeBtn; + private Button _unsubscribeBtn; + private Button _loadProfileBtn; + private Button _unloadProfileBtn; + private Button _saveProfileBtn; + private Button _rejectTrainingBtn; + private Button _eraseTrainingBtn; + private Button _acceptTrainingBtn; + private Button _startTrainingBtn; + private Button _stopRecordBtn; + private Button _injectMarkerBtn; + private Button _exportRecordBtn; + private Button _queryRecordBtn; // for android #if UNITY_ANDROID @@ -146,7 +161,8 @@ private static void RequestPermission(string permissionName) { void Start() { - + CacheButtonReferences(); + #if USE_EMBEDDED_LIB && UNITY_STANDALONE_WIN && !UNITY_EDITOR string[] args = Environment.GetCommandLineArgs(); if (args.Length > 1) @@ -188,8 +204,12 @@ void Update() // Check buttons interactable CheckButtonsInteractable(); - // Display message log - MessageLog.text = _eItf.MessageLog; + // Display message log only when it has changed + if (_eItf.MessageLog != _lastMessageLog) + { + _lastMessageLog = _eItf.MessageLog; + MessageLog.text = _eItf.MessageLog; + } // Demo how to get detected headset lists // List detectedHeadsets = _eItf.GetDetectedHeadsets(); @@ -280,13 +300,13 @@ public void onStopRecordBtnClick() { } // export record to desktop - public void onExportRecordBtnClick() + public async void onExportRecordBtnClick() { Debug.Log("onExportRecordBtnClick"); - string _recordId = _eItf.RecentRecord?.Uuid; + string _recordId = RecordId.text; if (string.IsNullOrEmpty(_recordId)) { - UnityEngine.Debug.Log("The recordId is empty. Please export with a valid recordId."); + UnityEngine.Debug.LogError("The recordId must not be empty. Please export with a valid recordId."); return; } @@ -308,9 +328,73 @@ public void onExportRecordBtnClick() List streamTypes = new List { "EEG", "MOTION" }; // Specify the stream types you want to export string format = "CSV"; // or "CSV", "EDFPLUS", "BDFPLUS" string version = "V2"; // Optional, specify if needed - _eItf.ExportRecord(recordsToExport, folderPath, streamTypes, format, version); + + try + { + ExportRecordResult result = await _eItf.ExportRecordAsync(recordsToExport, folderPath, streamTypes, format, version); + + string msgLog = "Export records - success: " + result.SuccessRecordIds.Count + ", failed: " + result.FailedRecords.Count + "\n"; + foreach (string recordId in result.SuccessRecordIds) + { + msgLog += "Success: " + recordId + "\n"; + } + foreach (ExportRecordFailure failure in result.FailedRecords) + { + msgLog += "Failed: " + failure.RecordId + " (code " + failure.Code + "): " + failure.Message + "\n"; + } + MessageLog.text = msgLog; + } + catch (Exception ex) + { + UnityEngine.Debug.LogError("onExportRecordBtnClick failed: " + ex.Message); + MessageLog.text = "Export records failed: " + ex.Message; + } } + // query records with a startDatetime range + public async void onQueryRecordBtnClick() + { + Debug.Log("onQueryRecordBtnClick"); + // demo to query with startDatetime range, the from and to are in ISO 8601 format + JObject query = new JObject( + new JProperty("startDatetime", new JObject( + new JProperty("from", "2026-01-06T16:32:50.572490+07:00"), + new JProperty("to", "2026-08-06T16:32:50.572490+07:00") + )) + ); + + // demo to query with keywords which can be record title or record note + // JObject query = new JObject( + // new JProperty("keyword", "123abc") + // ); + + // If you want to query records of owner but not created by the application, + // you can set the licenseId to filter the records. + // If you set the licenseId, then you can set this parameter to further filter the records by application. + // JObject query = new JObject( + // new JProperty("applicationId", "com.emotivid.appname"), + // new JProperty("licenseId", "xxx--yyy") + // ); + + try + { + List records = await _eItf.QueryRecords(query, null, 100, 0, true, true); + + string msgLog = "Query records: found " + records.Count + " record(s).\n"; + foreach (Record record in records) + { + msgLog += "RecordId: " + record.Uuid + ", Title: " + record.Title + ", StartTime: " + record.StartDateTime + + ", EndTime: " + record.EndDateTime + ", SyncStatus: " + record.SyncStatus + "\n"; + } + MessageLog.text = msgLog; + } + catch (Exception ex) + { + UnityEngine.Debug.LogError("onQueryRecordBtnClick failed: " + ex.Message); + MessageLog.text = "Query records failed: " + ex.Message; + } + } + public void onInjectMarkerBtnClick() { Debug.Log("onInjectMarkerBtnClick " + MarkerValue.text + ":" + MarkerLabel.text); @@ -417,51 +501,55 @@ void OnApplicationQuit() _eItf.Stop(); } + private void CacheButtonReferences() + { + _signInBtn = GameObject.Find("AuthenPart").transform.Find("signInBtn").GetComponent