| | 1 | | using System; |
| | 2 | | using System.Collections; |
| | 3 | | using System.Collections.Generic; |
| | 4 | | using DCL.Configuration; |
| | 5 | | using UnityEngine; |
| | 6 | | using DCL.Helpers; |
| | 7 | | using TMPro; |
| | 8 | | using UnityEngine.Networking; |
| | 9 | | using UnityEngine.UI; |
| | 10 | |
|
| | 11 | | namespace DCL.Builder |
| | 12 | | { |
| | 13 | | public interface IProjectCardView : IDisposable |
| | 14 | | { |
| | 15 | | /// <summary> |
| | 16 | | /// Edit project button pressed |
| | 17 | | /// </summary> |
| | 18 | | event Action<ProjectData> OnEditorPressed; |
| | 19 | |
|
| | 20 | | /// <summary> |
| | 21 | | /// Setting button pressed from the project card |
| | 22 | | /// </summary> |
| | 23 | | event Action<IProjectCardView> OnSettingsPressed; |
| | 24 | |
|
| | 25 | | /// <summary> |
| | 26 | | /// Setting button pressed from the sceneCard |
| | 27 | | /// </summary> |
| | 28 | | event Action<IProjectSceneCardView> OnSceneCardSettingsPressed; |
| | 29 | |
|
| | 30 | | /// <summary> |
| | 31 | | /// Expand button pressed |
| | 32 | | /// </summary> |
| | 33 | | event Action OnExpandMenuPressed; |
| | 34 | |
|
| | 35 | | /// <summary> |
| | 36 | | /// Data of the project card |
| | 37 | | /// </summary> |
| | 38 | | ProjectData projectData { get; } |
| | 39 | |
|
| | 40 | | /// <summary> |
| | 41 | | /// Info for the search result |
| | 42 | | /// </summary> |
| | 43 | | ISearchInfo searchInfo { get; } |
| | 44 | |
|
| | 45 | | /// <summary> |
| | 46 | | /// Position of the context menu button |
| | 47 | | /// </summary> |
| | 48 | | Vector3 contextMenuButtonPosition { get; } |
| | 49 | |
|
| | 50 | | /// <summary> |
| | 51 | | /// Set the scenes of the project |
| | 52 | | /// </summary> |
| | 53 | | /// <param name="scenes"></param> |
| | 54 | | void SetScenes(List<Scene> scenes); |
| | 55 | |
|
| | 56 | | /// <summary> |
| | 57 | | /// This setup the project data |
| | 58 | | /// </summary> |
| | 59 | | /// <param name="projectData"></param> |
| | 60 | | void Setup(ProjectData projectData); |
| | 61 | |
|
| | 62 | | /// <summary> |
| | 63 | | /// Set Parent of the card |
| | 64 | | /// </summary> |
| | 65 | | /// <param name="parent"></param> |
| | 66 | | void SetParent(Transform parent); |
| | 67 | |
|
| | 68 | | /// <summary> |
| | 69 | | /// Reset to default parent |
| | 70 | | /// </summary> |
| | 71 | | void SetToDefaultParent(); |
| | 72 | |
|
| | 73 | | /// <summary> |
| | 74 | | /// Configure the default parent |
| | 75 | | /// </summary> |
| | 76 | | /// <param name="parent">default parent to apply</param> |
| | 77 | | void ConfigureDefaultParent(Transform parent); |
| | 78 | |
|
| | 79 | | /// <summary> |
| | 80 | | /// Active the card |
| | 81 | | /// </summary> |
| | 82 | | /// <param name="active"></param> |
| | 83 | | void SetActive(bool active); |
| | 84 | |
|
| | 85 | | /// <summary> |
| | 86 | | /// This set the order of the card |
| | 87 | | /// </summary> |
| | 88 | | /// <param name="index"></param> |
| | 89 | | void SetSiblingIndex(int index); |
| | 90 | |
|
| | 91 | | void SetName(string name); |
| | 92 | | void SetSize(int rows, int columns); |
| | 93 | | void SetThumbnail(string thumbnailUrl, string filename); |
| | 94 | | void SetThumbnail(Texture2D thumbnailTexture); |
| | 95 | | } |
| | 96 | |
|
| | 97 | | internal class ProjectCardView : MonoBehaviour, IProjectCardView |
| | 98 | | { |
| 1 | 99 | | static readonly Vector3 CONTEXT_MENU_OFFSET = new Vector3(6.24f, 12f, 0); |
| | 100 | |
|
| | 101 | | internal const string NOT_PUBLISHED = "NOT PUBLISHED"; |
| | 102 | | internal const string PUBLISHED_IN = "PUBLISHED IN"; |
| | 103 | |
|
| | 104 | | internal const float SCENE_CARD_SIZE = 84; |
| | 105 | | internal const float SCENE_CARD_ITEM_PADDING = 18; |
| | 106 | | internal const float SCENE_CARD_TOTAL_PADDING = 36; |
| | 107 | |
|
| | 108 | | internal const float MS_TO_IGNORE_DUE_TO_SERVER = 20000; |
| | 109 | |
|
| | 110 | | public event Action<ProjectData> OnEditorPressed; |
| | 111 | | public event Action<IProjectCardView> OnSettingsPressed; |
| | 112 | | public event Action<IProjectSceneCardView> OnSceneCardSettingsPressed; |
| | 113 | | public event Action OnExpandMenuPressed; |
| | 114 | |
|
| | 115 | | [Header("Design Variables")] |
| 8 | 116 | | [SerializeField] private float animationSpeed = 6f; |
| | 117 | |
|
| | 118 | | [Header("Project References")] |
| | 119 | | [SerializeField] internal Color syncColor; |
| | 120 | |
|
| | 121 | | [SerializeField] internal Color desyncColor; |
| | 122 | | [SerializeField] private Texture2D defaultThumbnail; |
| | 123 | | [SerializeField] private GameObject projectSceneCardViewPrefab; |
| | 124 | |
|
| | 125 | | [Header("Prefab references")] |
| | 126 | | [SerializeField] internal Image syncImage; |
| | 127 | |
|
| | 128 | | [SerializeField] internal Button contextMenuButton; |
| | 129 | | [SerializeField] internal Button expandButton; |
| | 130 | | [SerializeField] internal Button editorButton; |
| | 131 | |
|
| | 132 | | [SerializeField] internal RectTransform scenesContainer; |
| | 133 | | [SerializeField] internal VerticalLayoutGroup layoutGroup; |
| | 134 | |
|
| | 135 | | [SerializeField] private GameObject loadingImgGameObject; |
| | 136 | | [SerializeField] private GameObject publishedGameObject; |
| | 137 | | [SerializeField] private RectTransform downButtonTransform; |
| | 138 | | [SerializeField] internal TextMeshProUGUI projectNameTxt; |
| | 139 | | [SerializeField] internal TextMeshProUGUI projectSizeTxt; |
| | 140 | | [SerializeField] internal TextMeshProUGUI projectSyncTxt; |
| | 141 | |
|
| | 142 | | [Space] |
| | 143 | | [SerializeField] private RawImageFillParent thumbnail; |
| | 144 | |
|
| 0 | 145 | | ProjectData IProjectCardView.projectData => projectData; |
| 30 | 146 | | ISearchInfo IProjectCardView.searchInfo { get; } = new SearchInfo(); |
| 0 | 147 | | Vector3 IProjectCardView.contextMenuButtonPosition => contextMenuButton.transform.position + CONTEXT_MENU_OFFSET |
| | 148 | |
|
| | 149 | | private ProjectData projectData; |
| | 150 | | private ISearchInfo searchInfo; |
| | 151 | | private Vector3 contextMenuButtonPosition; |
| | 152 | |
|
| | 153 | | private string thumbnailId = null; |
| | 154 | | private Transform defaultParent; |
| | 155 | | private bool scenesAreVisible = false; |
| | 156 | | private bool isDestroyed = false; |
| | 157 | |
|
| | 158 | | private RectTransform rectTransform; |
| | 159 | |
|
| 8 | 160 | | internal List<Scene> scenesDeployedFromProject = new List<Scene>(); |
| 8 | 161 | | internal List<IProjectSceneCardView> sceneCardViews = new List<IProjectSceneCardView>(); |
| | 162 | |
|
| | 163 | | private Coroutine animRectTransformCoroutine; |
| | 164 | | private Coroutine animContainerCoroutine; |
| | 165 | |
|
| | 166 | | private void Awake() |
| | 167 | | { |
| 7 | 168 | | editorButton.onClick.AddListener(EditorButtonClicked); |
| 7 | 169 | | expandButton.onClick.AddListener(ExpandButtonPressed); |
| 7 | 170 | | contextMenuButton.onClick.AddListener(ContextMenuPressed); |
| | 171 | |
|
| 7 | 172 | | rectTransform = GetComponent<RectTransform>(); |
| 7 | 173 | | } |
| | 174 | |
|
| | 175 | | private void OnDestroy() |
| | 176 | | { |
| 7 | 177 | | isDestroyed = true; |
| 7 | 178 | | Dispose(); |
| 7 | 179 | | } |
| | 180 | |
|
| | 181 | | public void Dispose() |
| | 182 | | { |
| 8 | 183 | | editorButton.onClick.RemoveAllListeners(); |
| 8 | 184 | | expandButton.onClick.RemoveAllListeners(); |
| 8 | 185 | | contextMenuButton.onClick.RemoveAllListeners(); |
| | 186 | |
|
| 8 | 187 | | CoroutineStarter.Stop(animRectTransformCoroutine); |
| 8 | 188 | | CoroutineStarter.Stop(animContainerCoroutine); |
| 8 | 189 | | if (!isDestroyed) |
| 1 | 190 | | Destroy(gameObject); |
| 8 | 191 | | } |
| | 192 | |
|
| | 193 | | public void Setup(ProjectData projectData) |
| | 194 | | { |
| 7 | 195 | | this.projectData = projectData; |
| 7 | 196 | | SetName(projectData.title); |
| 7 | 197 | | SetSize(projectData.rows, projectData.cols); |
| | 198 | |
|
| 7 | 199 | | SetThumbnail(projectData.id, projectData.thumbnail); |
| | 200 | |
|
| 7 | 201 | | ((IProjectCardView)this).searchInfo.SetId(projectData.id); |
| 7 | 202 | | } |
| | 203 | |
|
| | 204 | | public void SetScenes(List<Scene> scenes) |
| | 205 | | { |
| 4 | 206 | | scenesDeployedFromProject = scenes; |
| 4 | 207 | | publishedGameObject.gameObject.SetActive(true); |
| 4 | 208 | | if (scenes.Count == 0) |
| | 209 | | { |
| 1 | 210 | | expandButton.interactable = false; |
| 1 | 211 | | syncImage.gameObject.SetActive(false); |
| 1 | 212 | | projectSyncTxt.text = NOT_PUBLISHED; |
| 1 | 213 | | downButtonTransform.gameObject.SetActive(false); |
| 1 | 214 | | } |
| | 215 | | else |
| | 216 | | { |
| 3 | 217 | | expandButton.interactable = true; |
| 3 | 218 | | syncImage.gameObject.SetActive(true); |
| 3 | 219 | | downButtonTransform.gameObject.SetActive(true); |
| 3 | 220 | | bool isSync = true; |
| 3 | 221 | | long projectTimestamp = BIWUtils.ConvertToMilisecondsTimestamp(projectData.updated_at); |
| 11 | 222 | | foreach (Scene scene in scenes) |
| | 223 | | { |
| 3 | 224 | | if (scene.deployTimestamp + MS_TO_IGNORE_DUE_TO_SERVER < projectTimestamp) |
| | 225 | | { |
| 1 | 226 | | isSync = false; |
| 1 | 227 | | break; |
| | 228 | | } |
| | 229 | | } |
| | 230 | |
|
| 3 | 231 | | if (isSync) |
| 2 | 232 | | syncImage.color = syncColor; |
| | 233 | | else |
| 1 | 234 | | syncImage.color = desyncColor; |
| | 235 | |
|
| 3 | 236 | | projectSyncTxt.text = PUBLISHED_IN; |
| | 237 | | } |
| 3 | 238 | | } |
| | 239 | |
|
| | 240 | | internal void ExpandButtonPressed() |
| | 241 | | { |
| 1 | 242 | | if (scenesDeployedFromProject.Count == 0 ) |
| 0 | 243 | | return; |
| | 244 | |
|
| 1 | 245 | | downButtonTransform.Rotate(Vector3.forward, 180); |
| | 246 | |
|
| 1 | 247 | | scenesAreVisible = !scenesAreVisible; |
| 1 | 248 | | ScenesVisiblitityChange(scenesAreVisible); |
| | 249 | |
|
| 1 | 250 | | float amountToIncrease = sceneCardViews.Count * SCENE_CARD_SIZE + SCENE_CARD_TOTAL_PADDING + SCENE_CARD_ITEM |
| | 251 | |
|
| 1 | 252 | | CoroutineStarter.Stop(animRectTransformCoroutine); |
| 1 | 253 | | CoroutineStarter.Stop(animContainerCoroutine); |
| 1 | 254 | | if (scenesAreVisible) |
| | 255 | | { |
| 1 | 256 | | layoutGroup.padding.bottom = 18; |
| 1 | 257 | | animRectTransformCoroutine = AddRectTransformHeight(rectTransform, amountToIncrease); |
| 1 | 258 | | animContainerCoroutine = AddRectTransformHeight(scenesContainer, amountToIncrease); |
| 1 | 259 | | } |
| | 260 | | else |
| | 261 | | { |
| 0 | 262 | | layoutGroup.padding.bottom = 0; |
| 0 | 263 | | animRectTransformCoroutine = AddRectTransformHeight(rectTransform, -amountToIncrease); |
| 0 | 264 | | animContainerCoroutine = AddRectTransformHeight(scenesContainer, -amountToIncrease); |
| | 265 | | } |
| | 266 | |
|
| 1 | 267 | | OnExpandMenuPressed?.Invoke(); |
| 1 | 268 | | } |
| | 269 | |
|
| 2 | 270 | | private Coroutine AddRectTransformHeight(RectTransform rectTransform, float height) { return CoroutineStarter.St |
| | 271 | |
|
| | 272 | | private void ScenesVisiblitityChange(bool isVisible) |
| | 273 | | { |
| 1 | 274 | | if (sceneCardViews.Count == 0) |
| 1 | 275 | | InstantiateScenesCards(); |
| | 276 | |
|
| 4 | 277 | | foreach (IProjectSceneCardView scene in sceneCardViews) |
| | 278 | | { |
| 1 | 279 | | scene.SetActive(isVisible); |
| | 280 | | } |
| 1 | 281 | | } |
| | 282 | |
|
| | 283 | | private void InstantiateScenesCards() |
| | 284 | | { |
| 1 | 285 | | long projectTimestamp = BIWUtils.ConvertToMilisecondsTimestamp(projectData.updated_at); |
| 4 | 286 | | foreach (Scene scene in scenesDeployedFromProject) |
| | 287 | | { |
| 1 | 288 | | bool isSync = scene.deployTimestamp + MS_TO_IGNORE_DUE_TO_SERVER >= projectTimestamp; |
| | 289 | |
|
| 1 | 290 | | IProjectSceneCardView cardView = Instantiate(projectSceneCardViewPrefab, scenesContainer).GetComponent<P |
| 1 | 291 | | cardView.Setup(scene, isSync); |
| 1 | 292 | | cardView.OnSettingsPressed += OnSceneCardSettingsPressed; |
| 1 | 293 | | sceneCardViews.Add(cardView); |
| | 294 | | } |
| 1 | 295 | | } |
| | 296 | |
|
| 2 | 297 | | internal void EditorButtonClicked() { OnEditorPressed?.Invoke(projectData); } |
| | 298 | |
|
| | 299 | | public void SetThumbnail(string thumbnailId, string thumbnailEndpoint) |
| | 300 | | { |
| 7 | 301 | | if (this.thumbnailId == thumbnailId) |
| 0 | 302 | | return; |
| | 303 | |
|
| 7 | 304 | | string projectThumbnailUrl = ""; |
| 7 | 305 | | if (!string.IsNullOrEmpty(thumbnailId)) |
| | 306 | | { |
| 0 | 307 | | projectThumbnailUrl = BIWUrlUtils.GetBuilderProjecThumbnailUrl(thumbnailId, thumbnailEndpoint); |
| | 308 | | } |
| | 309 | |
|
| 7 | 310 | | this.thumbnailId = thumbnailId; |
| | 311 | |
|
| 7 | 312 | | if (string.IsNullOrEmpty(projectThumbnailUrl)) |
| | 313 | | { |
| 7 | 314 | | SetThumbnail((Texture2D) null); |
| 7 | 315 | | return; |
| | 316 | | } |
| | 317 | |
|
| 0 | 318 | | loadingImgGameObject.SetActive(true); |
| 0 | 319 | | thumbnail.enabled = false; |
| | 320 | |
|
| 0 | 321 | | GetThumbnail(projectThumbnailUrl); |
| 0 | 322 | | } |
| | 323 | |
|
| | 324 | | public void GetThumbnail(string url) |
| | 325 | | { |
| 0 | 326 | | Dictionary<string, string> headers = new Dictionary<string, string>(); |
| 0 | 327 | | headers["Cache-Control"] = "no-cache, no-store, must-revalidate"; |
| 0 | 328 | | Environment.i.platform.webRequest.GetTexture( |
| | 329 | | url: url, |
| | 330 | | OnSuccess: (webRequestResult) => |
| | 331 | | { |
| 0 | 332 | | Texture2D texture2D = DownloadHandlerTexture.GetContent(webRequestResult.webRequest); |
| 0 | 333 | | SetThumbnail(texture2D); |
| 0 | 334 | | }, |
| | 335 | | OnFail: (webRequestResult) => |
| | 336 | | { |
| 0 | 337 | | Debug.Log(webRequestResult.webRequest.error); |
| 0 | 338 | | loadingImgGameObject.SetActive(false); |
| 0 | 339 | | }, |
| | 340 | | headers: headers); |
| 0 | 341 | | } |
| | 342 | |
|
| | 343 | | public void SetThumbnail(Texture2D thumbnailTexture) |
| | 344 | | { |
| 7 | 345 | | loadingImgGameObject.SetActive(false); |
| 7 | 346 | | thumbnail.texture = thumbnailTexture ?? defaultThumbnail; |
| 7 | 347 | | thumbnail.enabled = true; |
| 7 | 348 | | } |
| | 349 | |
|
| | 350 | | public void SetParent(Transform parent) |
| | 351 | | { |
| 0 | 352 | | if (transform.parent == parent) |
| 0 | 353 | | return; |
| | 354 | |
|
| 0 | 355 | | transform.SetParent(parent); |
| 0 | 356 | | transform.ResetLocalTRS(); |
| 0 | 357 | | } |
| | 358 | |
|
| 2 | 359 | | public void SetToDefaultParent() { transform.SetParent(defaultParent); } |
| | 360 | |
|
| 2 | 361 | | public void ConfigureDefaultParent(Transform parent) { defaultParent = parent; } |
| | 362 | |
|
| 2 | 363 | | public void SetActive(bool active) { gameObject.SetActive(active); } |
| | 364 | |
|
| 0 | 365 | | public void SetSiblingIndex(int index) { transform.SetSiblingIndex(index); } |
| | 366 | |
|
| | 367 | | public void SetName(string name) |
| | 368 | | { |
| 7 | 369 | | projectNameTxt.text = name; |
| 7 | 370 | | ((IProjectCardView)this).searchInfo.SetName(name); |
| 7 | 371 | | } |
| | 372 | |
|
| | 373 | | public void SetSize(int rows, int columns) |
| | 374 | | { |
| 7 | 375 | | projectSizeTxt.text = GetSizeText(rows, columns); |
| 7 | 376 | | ((IProjectCardView)this).searchInfo.SetSize(rows * columns); |
| 7 | 377 | | } |
| | 378 | |
|
| 0 | 379 | | private void ContextMenuPressed() { OnSettingsPressed?.Invoke(this); } |
| | 380 | |
|
| 8 | 381 | | internal string GetSizeText(int rows, int columns) { return (rows * ParcelSettings.PARCEL_SIZE) + "x" + (columns |
| | 382 | |
|
| | 383 | | IEnumerator ChangeHeightAnimation(RectTransform rectTransform, float height) |
| | 384 | | { |
| 2 | 385 | | float time = 0; |
| | 386 | |
|
| 2 | 387 | | Vector2 rect2 = rectTransform.sizeDelta; |
| 2 | 388 | | float objective = rect2.y + height; |
| | 389 | |
|
| 2 | 390 | | while (time < 1) |
| | 391 | | { |
| 2 | 392 | | time += Time.deltaTime * animationSpeed / scenesDeployedFromProject.Count; |
| 2 | 393 | | rect2.y = Mathf.Lerp(rect2.y, objective, time); |
| 2 | 394 | | rectTransform.sizeDelta = rect2; |
| 2 | 395 | | yield return null; |
| | 396 | | } |
| 0 | 397 | | } |
| | 398 | | } |
| | 399 | | } |