feat: Add ongoing event list view

This commit is contained in:
2025-02-16 12:34:04 +08:00
parent def9d6d232
commit 06e4f5bf9f
8 changed files with 1046 additions and 12 deletions

View File

@@ -0,0 +1,69 @@
using System;
using UnityEngine;
namespace Utils {
public class PropertyTweener<T> {
readonly Func<T> _getter;
readonly Action<T> _setter;
readonly Tweener<T> _tweener;
public PropertyTweener(Func<T> getter, Action<T> setter, Tweener<T> tweener) {
_getter = getter;
_setter = setter;
_tweener = tweener;
}
public PropertyTweener<T> Start(T endValue, float duration) {
_tweener.Start(_getter(), endValue, duration);
return this;
}
public void Advance(float deltaTime) {
_setter(_tweener.Advance(deltaTime));
}
}
public class Tweener<T> {
readonly Func<T, T, T> _addition;
readonly Func<float, T, T> _multiplication;
public Tweener(Func<T, T, T> addition, Func<float, T, T> multiplication) {
_addition = addition;
_multiplication = multiplication;
}
public Func<float, float> EasingFunction { get; set; } = EasingFunctions.Linear;
public Tweener<T> SetEasingFunction(Func<float, float> easing) {
EasingFunction = easing;
return this;
}
T _startValue = default;
T _endValue = default;
float _duration = float.PositiveInfinity;
float _time;
public Tweener<T> Start(T startValue, T endValue, float duration) {
_startValue = startValue;
_endValue = endValue;
_duration = duration;
_time = 0;
return this;
}
public T Advance(float deltaTime) {
_time += deltaTime;
var ratio = EasingFunction(Math.Clamp(_time / _duration, 0, 1));
return _addition(_multiplication(1 - ratio, _startValue), _multiplication(ratio, _endValue));
}
}
public static class Tweeners {
public static Tweener<int> Int32 => new((a, b) => a + b, (k, v) => (int)(k * v));
public static Tweener<float> Single => new((a, b) => a + b, (k, v) => k * v);
public static Tweener<double> Double => new((a, b) => a + b, (k, v) => k * v);
public static Tweener<Vector2> Vector2 => new((a, b) => a + b, (k, v) => k * v);
public static Tweener<Vector3> Vector3 => new((a, b) => a + b, (k, v) => k * v);
public static Tweener<Quaternion> Quaternion => new((a, b) => a * b, (k, v) => UnityEngine.Quaternion.Slerp(UnityEngine.Quaternion.identity, v, k));
}
public static class EasingFunctions {
public static float Linear(float x) => x;
public static float InQuad(float x) => x * x;
public static float InCubic(float x) => x * x * x;
public static float InSine(float x) => 1 - OutSine(1 - x);
public static float OutQuad(float x) => 1 - InQuad(1 - x);
public static float OutCubic(float x) => 1 - InCubic(1 - x);
public static float OutSine(float x) => MathF.Sin(x * MathF.PI / 2);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0d8c4d69179c5e644bd48565ec4c8258
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -6,18 +6,38 @@ using UnityEngine;
namespace Cryville.EEW.Unity.UI { namespace Cryville.EEW.Unity.UI {
class EventOngoingListView : MonoBehaviour { class EventOngoingListView : MonoBehaviour {
public static EventOngoingListView Instance { get; private set; }
[SerializeField] EventReportView m_currentView; [SerializeField] EventReportView m_currentView;
[SerializeField] Transform m_listView;
[SerializeField] EventOngoingView m_prefabEventOngoingView;
readonly List<ReportViewModel> _displayingReports = new(); readonly List<ReportViewModel> _displayingReports = new();
readonly List<EventOngoingView> _displayingViews = new();
public void Add(ReportViewModel e) { public void Add(ReportViewModel e) {
_displayingReports.Add(e); _displayingReports.Add(e);
var child = Instantiate(m_prefabEventOngoingView);
child.SetViewModel(e);
child.transform.SetParent(m_listView, false);
_displayingViews.Add(child);
SwitchTo(_displayingReports.Count - 1); SwitchTo(_displayingReports.Count - 1);
if (_displayingReports.Count > 1) m_listView.gameObject.SetActive(true);
} }
public void Remove(ReportViewModel e) { public void Remove(ReportViewModel e) {
int index = _displayingReports.IndexOf(e); int index = _displayingReports.IndexOf(e);
if (index == -1) return; if (index == -1) return;
_displayingReports.RemoveAt(index); _displayingReports.RemoveAt(index);
var child = m_listView.GetChild(index);
child.SetParent(null, false);
Destroy(child.gameObject);
_displayingViews.RemoveAt(index);
if (_displayingReports.Count == 0) { if (_displayingReports.Count == 0) {
m_currentView.gameObject.SetActive(false); m_currentView.gameObject.SetActive(false);
} }
@@ -25,8 +45,17 @@ namespace Cryville.EEW.Unity.UI {
if (_index > index) --_index; if (_index > index) --_index;
else if (_index == index) SwitchTo(index % _displayingReports.Count); else if (_index == index) SwitchTo(index % _displayingReports.Count);
} }
if (_displayingReports.Count <= 1) m_listView.gameObject.SetActive(false);
} }
void Awake() {
if (Instance != null) {
Destroy(this);
throw new InvalidOperationException("Duplicate ongoing list view.");
}
Instance = this;
}
void Start() { void Start() {
m_currentView.gameObject.SetActive(false); m_currentView.gameObject.SetActive(false);
} }
@@ -41,12 +70,20 @@ namespace Cryville.EEW.Unity.UI {
} }
} }
void SwitchTo(int index) { void SwitchTo(int index) {
if (_index < _displayingReports.Count)
_displayingViews[_index].SetCurrent(false);
_index = index; _index = index;
var e = _displayingReports[index]; var e = _displayingReports[index];
m_currentView.SetViewModel(e, true); m_currentView.SetViewModel(e, true);
var keyProp = e.Properties.FirstOrDefault(); var keyProp = e.Properties.FirstOrDefault();
_displayingViews[_index].SetCurrent(true);
_tickDown = Math.Max(0, keyProp?.Severity ?? 0) * 4 + 4; _tickDown = Math.Max(0, keyProp?.Severity ?? 0) * 4 + 4;
m_currentView.gameObject.SetActive(true); m_currentView.gameObject.SetActive(true);
} }
public void SetCurrent(ReportViewModel viewModel) {
int index = _displayingReports.IndexOf(viewModel);
if (index == -1) return;
SwitchTo(index);
}
} }
} }

View File

@@ -0,0 +1,65 @@
using Cryville.Common.Unity.UI;
using Cryville.EEW.Report;
using System;
using System.Globalization;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using Utils;
using static UnityEditor.Profiling.HierarchyFrameDataView;
namespace Cryville.EEW.Unity.UI {
class EventOngoingView : MonoBehaviour {
[SerializeField] Image[] m_reportView;
[SerializeField] Button m_button;
[SerializeField] TMPLocalizedText m_textView;
[SerializeField] DockOccupiedRatioLayoutGroup m_dockLayoutGroup;
ReportViewModel _viewModel;
void SetSeverity(float severity) {
var color = SharedSettings.Instance.SeverityColorMapping.From(severity);
SetMainColor(color.ToSrgb().ToUnityColor());
}
protected virtual void SetMainColor(Color color) {
foreach (var view in m_reportView)
view.color = color;
}
void SetView(float mainSeverity, string title, string location, CultureInfo culture) {
SetSeverity(mainSeverity);
SetText(m_textView, string.Format("{0} {1}", title, location), culture);
}
static void SetText(TMPLocalizedText view, string text, CultureInfo culture) {
if (string.IsNullOrWhiteSpace(text)) {
view.gameObject.SetActive(false);
return;
}
view.gameObject.SetActive(true);
view.SetText(text, culture);
}
public void SetViewModel(ReportViewModel e) {
_viewModel = e;
SetView(e.Properties.FirstOrDefault()?.Severity ?? -1, e.Title, e.Location, e.Culture);
}
PropertyTweener<float> _dockRatioTweener;
void Awake() {
_dockRatioTweener = new(() => m_dockLayoutGroup.DockOccupiedRatio, v => m_dockLayoutGroup.DockOccupiedRatio = v, Tweeners.Single);
}
void Start() {
m_button.onClick.AddListener(OnViewClicked);
}
void OnViewClicked() {
EventOngoingListView.Instance.SetCurrent(_viewModel);
}
void Update() {
_dockRatioTweener.Advance(Time.deltaTime);
}
public void SetCurrent(bool v) {
_dockRatioTweener.Start(v ? 1 : 0.75f, 0.1f);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0a3acd791541c4345a6a5ca7dfa8f046
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -133,6 +133,7 @@ GameObject:
m_Component: m_Component:
- component: {fileID: 234130748} - component: {fileID: 234130748}
- component: {fileID: 234130749} - component: {fileID: 234130749}
- component: {fileID: 234130750}
m_Layer: 5 m_Layer: 5
m_Name: Current m_Name: Current
m_TagString: Untagged m_TagString: Untagged
@@ -175,9 +176,9 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_Padding: m_Padding:
m_Left: 6 m_Left: 6
m_Right: 6 m_Right: 0
m_Top: 6 m_Top: 6
m_Bottom: 6 m_Bottom: 0
m_ChildAlignment: 0 m_ChildAlignment: 0
m_ChildForceExpandWidth: 1 m_ChildForceExpandWidth: 1
m_ChildForceExpandHeight: 0 m_ChildForceExpandHeight: 0
@@ -185,6 +186,26 @@ MonoBehaviour:
m_ChildControlHeight: 1 m_ChildControlHeight: 1
m_ChildScaleWidth: 0 m_ChildScaleWidth: 0
m_ChildScaleHeight: 0 m_ChildScaleHeight: 0
--- !u!114 &234130750
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 234130747}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
m_Name:
m_EditorClassIdentifier:
m_IgnoreLayout: 0
m_MinWidth: -1
m_MinHeight: 240
m_PreferredWidth: -1
m_PreferredHeight: -1
m_FlexibleWidth: -1
m_FlexibleHeight: -1
m_LayoutPriority: 1
--- !u!1 &239371813 --- !u!1 &239371813
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -583,11 +604,11 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_Padding: m_Padding:
m_Left: 0 m_Left: 0
m_Right: 0 m_Right: 6
m_Top: 0 m_Top: 0
m_Bottom: 0 m_Bottom: 0
m_ChildAlignment: 0 m_ChildAlignment: 0
m_Spacing: 0 m_Spacing: 16
m_ChildForceExpandWidth: 0 m_ChildForceExpandWidth: 0
m_ChildForceExpandHeight: 0 m_ChildForceExpandHeight: 0
m_ChildControlWidth: 1 m_ChildControlWidth: 1
@@ -608,6 +629,8 @@ MonoBehaviour:
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_currentView: {fileID: 8447618677709876516} m_currentView: {fileID: 8447618677709876516}
m_listView: {fileID: 917542012}
m_prefabEventOngoingView: {fileID: 7245722805295636253, guid: 2310ef60ea9bf8244bbf5ba373c1de9c, type: 3}
--- !u!1 &800505389 --- !u!1 &800505389
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -655,13 +678,14 @@ GameObject:
m_Component: m_Component:
- component: {fileID: 917542012} - component: {fileID: 917542012}
- component: {fileID: 917542013} - component: {fileID: 917542013}
- component: {fileID: 917542014}
m_Layer: 5 m_Layer: 5
m_Name: List m_Name: List
m_TagString: Untagged m_TagString: Untagged
m_Icon: {fileID: 0} m_Icon: {fileID: 0}
m_NavMeshLayer: 0 m_NavMeshLayer: 0
m_StaticEditorFlags: 0 m_StaticEditorFlags: 0
m_IsActive: 1 m_IsActive: 0
--- !u!224 &917542012 --- !u!224 &917542012
RectTransform: RectTransform:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -677,10 +701,10 @@ RectTransform:
m_Father: {fileID: 719162187} m_Father: {fileID: 719162187}
m_RootOrder: 1 m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0} m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 0, y: 0} m_AnchoredPosition: {x: 157, y: -176}
m_SizeDelta: {x: 0, y: 0} m_SizeDelta: {x: 314, y: 0}
m_Pivot: {x: 0.5, y: 0.5} m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &917542013 --- !u!114 &917542013
MonoBehaviour: MonoBehaviour:
@@ -695,19 +719,39 @@ MonoBehaviour:
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_Padding: m_Padding:
m_Left: 0 m_Left: -16
m_Right: 0 m_Right: 0
m_Top: 0 m_Top: 0
m_Bottom: 0 m_Bottom: 0
m_ChildAlignment: 0 m_ChildAlignment: 0
m_Spacing: 0 m_Spacing: 4
m_ChildForceExpandWidth: 0 m_ChildForceExpandWidth: 1
m_ChildForceExpandHeight: 0 m_ChildForceExpandHeight: 0
m_ChildControlWidth: 1 m_ChildControlWidth: 1
m_ChildControlHeight: 1 m_ChildControlHeight: 1
m_ChildScaleWidth: 0 m_ChildScaleWidth: 0
m_ChildScaleHeight: 1 m_ChildScaleHeight: 1
m_ReverseArrangement: 0 m_ReverseArrangement: 0
--- !u!114 &917542014
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 917542011}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
m_Name:
m_EditorClassIdentifier:
m_IgnoreLayout: 0
m_MinWidth: -1
m_MinHeight: -1
m_PreferredWidth: -1
m_PreferredHeight: -1
m_FlexibleWidth: 1
m_FlexibleHeight: -1
m_LayoutPriority: 1
--- !u!1 &1345962671 --- !u!1 &1345962671
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 2310ef60ea9bf8244bbf5ba373c1de9c
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: