TH1/Unity/Assets/Scripts/TH1_DataAssetsScript/QuestionnaireDataAssets.cs

212 lines
6.9 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
using Logic.Multilingual;
using UnityEngine;
public enum QuestionnaireQuestionType
{
Open = 0,
SingleChoice = 1,
MultipleChoice = 2
}
public enum QuestionnaireStatus
{
Featured = 0,
LongTerm = 1,
Expired = 2,
Hidden = 3
}
[Serializable]
[CreateAssetMenu(fileName = "QuestionnaireDataAssets", menuName = "TH1 Game Data/Questionnaire Data Asset")]
public class QuestionnaireDataAssets : ScriptableObject
{
public string DefaultQuestionnaireId = "player-feedback-2026-06";
[MultilingualField] public string MenuButtonText;
public List<QuestionnaireInfo> QuestionnaireList = new List<QuestionnaireInfo>();
[NonSerialized]
private Dictionary<string, QuestionnaireInfo> _questionnaireDict;
public QuestionnaireInfo GetDefaultQuestionnaire()
{
if (GetQuestionnaireInfo(DefaultQuestionnaireId, out var info)) return info;
return QuestionnaireList != null && QuestionnaireList.Count > 0 ? QuestionnaireList[0] : null;
}
public List<QuestionnaireInfo> GetVisibleQuestionnaires(DateTime? nowUtc = null)
{
var result = new List<QuestionnaireInfo>();
if (QuestionnaireList == null) return result;
var now = nowUtc ?? DateTime.UtcNow;
foreach (var info in QuestionnaireList)
{
if (info == null || !info.IsVisibleAt(now)) continue;
result.Add(info);
}
result.Sort(CompareQuestionnaire);
return result;
}
public bool GetQuestionnaireInfo(string questionnaireId, out QuestionnaireInfo info)
{
EnsureDict();
if (!string.IsNullOrEmpty(questionnaireId) && _questionnaireDict.TryGetValue(questionnaireId, out info))
{
return true;
}
info = null;
return false;
}
private void EnsureDict()
{
if (_questionnaireDict != null && QuestionnaireList != null && _questionnaireDict.Count == QuestionnaireList.Count)
{
return;
}
_questionnaireDict = new Dictionary<string, QuestionnaireInfo>();
if (QuestionnaireList == null) return;
foreach (var info in QuestionnaireList)
{
if (info == null || string.IsNullOrEmpty(info.QuestionnaireId)) continue;
_questionnaireDict[info.QuestionnaireId] = info;
}
}
private static int CompareQuestionnaire(QuestionnaireInfo left, QuestionnaireInfo right)
{
var statusCompare = GetStatusRank(left?.Status ?? QuestionnaireStatus.Hidden)
.CompareTo(GetStatusRank(right?.Status ?? QuestionnaireStatus.Hidden));
if (statusCompare != 0) return statusCompare;
var priorityCompare = (right?.Priority ?? 0).CompareTo(left?.Priority ?? 0);
if (priorityCompare != 0) return priorityCompare;
return string.Compare(left?.QuestionnaireId, right?.QuestionnaireId, StringComparison.Ordinal);
}
private static int GetStatusRank(QuestionnaireStatus status)
{
return status switch
{
QuestionnaireStatus.Featured => 0,
QuestionnaireStatus.LongTerm => 1,
QuestionnaireStatus.Expired => 2,
_ => 3
};
}
}
[Serializable]
public class QuestionnaireInfo
{
public string QuestionnaireId;
public int Revision = 1;
public QuestionnaireStatus Status = QuestionnaireStatus.LongTerm;
public int Priority;
public string StartAtUtc;
public string EndAtUtc;
public bool AllowMultipleSubmissions = true;
public int MaxSubmissionCount;
public int MinSubmitIntervalHours;
public bool CanViewHistory = true;
public bool CanSubmitAfterExpired;
public QuestionnaireTargetRules TargetRules = new QuestionnaireTargetRules();
[MultilingualField] public string Title;
[MultilingualField] public string Description;
[MultilingualField] public string StartButtonText;
[MultilingualField] public string SubmitButtonText;
[MultilingualField] public string ResubmitButtonText;
[MultilingualField] public string CloseButtonText;
[MultilingualField] public string SubmittedMessage;
[MultilingualField] public string UploadingMessage;
[MultilingualField] public string UploadSuccessMessage;
[MultilingualField] public string UploadFailedMessage;
[MultilingualField] public string UploadAuthFailedMessage;
[MultilingualField] public string RequiredMessage;
[MultilingualField] public string RefillHintText;
[MultilingualField] public string SaveFailedMessage;
public List<QuestionnaireQuestionInfo> Questions = new List<QuestionnaireQuestionInfo>();
public QuestionnaireStatus GetEffectiveStatus(DateTime utcNow)
{
if (Status == QuestionnaireStatus.Hidden) return QuestionnaireStatus.Hidden;
if (Status == QuestionnaireStatus.Expired) return QuestionnaireStatus.Expired;
if (HasEnded(utcNow) && !CanSubmitAfterExpired) return QuestionnaireStatus.Expired;
return Status;
}
public bool IsVisibleAt(DateTime utcNow)
{
if (Status == QuestionnaireStatus.Hidden) return false;
if (!HasStarted(utcNow)) return false;
return true;
}
public bool CanSubmitAt(DateTime utcNow)
{
if (Status == QuestionnaireStatus.Hidden) return false;
if (Status == QuestionnaireStatus.Expired && !CanSubmitAfterExpired) return false;
if (!HasStarted(utcNow)) return false;
if (HasEnded(utcNow) && !CanSubmitAfterExpired) return false;
return true;
}
private bool HasStarted(DateTime utcNow)
{
return !TryParseUtc(StartAtUtc, out var startAt) || utcNow >= startAt;
}
private bool HasEnded(DateTime utcNow)
{
return TryParseUtc(EndAtUtc, out var endAt) && utcNow > endAt;
}
private static bool TryParseUtc(string raw, out DateTime value)
{
value = default;
if (string.IsNullOrWhiteSpace(raw)) return false;
return DateTime.TryParse(raw, CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out value);
}
}
[Serializable]
public class QuestionnaireTargetRules
{
public List<string> VersionWhitelist = new List<string>();
public List<string> PlatformWhitelist = new List<string>();
public List<string> LanguageWhitelist = new List<string>();
public bool SteamOnly;
public bool BetaOnly;
public int MinFinishedMatchCount;
}
[Serializable]
public class QuestionnaireQuestionInfo
{
public string QuestionId;
public QuestionnaireQuestionType QuestionType;
[MultilingualField] public string Title;
[MultilingualField] public string Hint;
public bool Required;
public int MaxSelectCount;
public List<QuestionnaireOptionInfo> Options = new List<QuestionnaireOptionInfo>();
}
[Serializable]
public class QuestionnaireOptionInfo
{
public string OptionId;
[MultilingualField] public string Text;
}