| | 1 | | using DCL.Helpers; |
| | 2 | | using DCL.Interface; |
| | 3 | | using System; |
| | 4 | | using TMPro; |
| | 5 | | using UnityEngine; |
| | 6 | | using UnityEngine.Serialization; |
| | 7 | | using UnityEngine.UI; |
| | 8 | |
|
| | 9 | | namespace DCL |
| | 10 | | { |
| | 11 | | public class NavmapToastView : MonoBehaviour |
| | 12 | | { |
| 1 | 13 | | private static readonly int triggerLoadingComplete = Animator.StringToHash("LoadingComplete"); |
| | 14 | |
|
| | 15 | | public event Action<string, bool> OnFavoriteToggleClicked; |
| | 16 | | public event Action<int, int> OnGoto; |
| | 17 | | public event Action OnInfoClick; |
| | 18 | | public event Action<string, bool?> OnVoteChanged; |
| | 19 | | public event Action<Vector2Int> OnPressedLinkCopy; |
| | 20 | | public event Action<Vector2Int, string> OnPressedTwitterButton; |
| | 21 | |
|
| | 22 | | [SerializeField] internal TextMeshProUGUI sceneTitleText; |
| | 23 | | [SerializeField] internal TextMeshProUGUI sceneOwnerText; |
| | 24 | | [SerializeField] internal TextMeshProUGUI sceneLocationText; |
| | 25 | | [SerializeField] internal TextMeshProUGUI playerCountText; |
| | 26 | | [SerializeField] internal TextMeshProUGUI userVisitsText; |
| | 27 | | [SerializeField] internal TextMeshProUGUI userRatingText; |
| | 28 | | [SerializeField] internal RectTransform numberOfUsersContainer; |
| | 29 | | [SerializeField] internal RectTransform userVisitsAndRatingContainer; |
| | 30 | | [SerializeField] internal RectTransform toastContainer; |
| | 31 | | [SerializeField] internal GameObject scenePreviewContainer; |
| | 32 | | [SerializeField] internal RawImageFillParent scenePreviewImage; |
| | 33 | | [SerializeField] internal Sprite scenePreviewFailImage; |
| | 34 | | [SerializeField] internal Animator toastAnimator; |
| | 35 | | [SerializeField] internal Image infoButtonImage; |
| | 36 | | [SerializeField] internal Image favoriteButtonImage; |
| | 37 | | [SerializeField] internal Sprite normalFavorite; |
| | 38 | | [SerializeField] internal Sprite blockedFavorite; |
| | 39 | | [SerializeField] internal Color normalImageColor; |
| | 40 | | [SerializeField] internal Color disabledImageColor; |
| | 41 | |
|
| | 42 | | [SerializeField] internal Button goToButton; |
| | 43 | | [SerializeField] internal Button infoButton; |
| | 44 | | [SerializeField] internal Button shareButton; |
| | 45 | | [SerializeField] internal FavoriteButtonComponentView favoriteToggle; |
| | 46 | | [SerializeField] internal GameObject favoriteLoading; |
| | 47 | | [SerializeField] internal ButtonComponentView upvoteButton; |
| | 48 | | [SerializeField] internal ButtonComponentView downvoteButton; |
| | 49 | | [SerializeField] internal GameObject upvoteOff; |
| | 50 | | [SerializeField] internal GameObject upvoteOn; |
| | 51 | | [SerializeField] internal GameObject downvoteOff; |
| | 52 | | [SerializeField] internal GameObject downvoteOn; |
| | 53 | | [SerializeField] internal PlaceCopyContextualMenu placeCopyContextualMenu; |
| | 54 | |
|
| | 55 | | [field: SerializeField] |
| | 56 | | [Tooltip("Distance in units")] |
| 4 | 57 | | internal float distanceToCloseView { get; private set; } = 500; |
| | 58 | |
|
| | 59 | | Vector2Int location; |
| | 60 | | RectTransform rectTransform; |
| | 61 | | MinimapMetadata minimapMetadata; |
| | 62 | | private MinimapMetadata.MinimapSceneInfo sceneInfo; |
| | 63 | |
|
| | 64 | | AssetPromise_Texture texturePromise; |
| | 65 | | string currentImageUrl; |
| | 66 | | private bool placeIsUpvote; |
| | 67 | | private bool placeIsDownvote; |
| | 68 | | private string placeId; |
| | 69 | |
|
| | 70 | | public void Open(Vector2Int parcel, Vector2 worldPosition) |
| | 71 | | { |
| 0 | 72 | | if (gameObject.activeInHierarchy) |
| 0 | 73 | | Close(); |
| | 74 | |
|
| 0 | 75 | | var sceneInfo = minimapMetadata.GetSceneInfo(parcel.x, parcel.y); |
| 0 | 76 | | if (sceneInfo == null) |
| 0 | 77 | | WebInterface.RequestScenesInfoAroundParcel(parcel, 15); |
| | 78 | |
|
| 0 | 79 | | Populate(parcel, worldPosition, sceneInfo); |
| 0 | 80 | | } |
| | 81 | |
|
| | 82 | | private void Awake() |
| | 83 | | { |
| 1 | 84 | | favoriteToggle.OnFavoriteChange += (uuid, isFavorite) => OnFavoriteToggleClicked?.Invoke(uuid, isFavorite); |
| 1 | 85 | | infoButton.onClick.RemoveAllListeners(); |
| 1 | 86 | | infoButton.onClick.AddListener(()=>OnInfoClick?.Invoke()); |
| 1 | 87 | | minimapMetadata = MinimapMetadata.GetMetadata(); |
| 1 | 88 | | rectTransform = transform as RectTransform; |
| 1 | 89 | | if(upvoteButton != null) |
| 1 | 90 | | upvoteButton.onClick.AddListener(() => ChangeVote(true)); |
| | 91 | |
|
| 1 | 92 | | if(downvoteButton != null) |
| 1 | 93 | | downvoteButton.onClick.AddListener(() => ChangeVote(false)); |
| | 94 | |
|
| 1 | 95 | | shareButton.onClick.RemoveAllListeners(); |
| 1 | 96 | | shareButton.onClick.AddListener(OpenShareContextMenu); |
| | 97 | |
|
| 1 | 98 | | placeCopyContextualMenu.OnPlaceLinkCopied += OnLinkCopied; |
| 1 | 99 | | placeCopyContextualMenu.OnTwitter += OnOpenTwitter; |
| | 100 | |
|
| 1 | 101 | | placeCopyContextualMenu.Hide(true); |
| 1 | 102 | | } |
| | 103 | |
|
| | 104 | | private void OpenShareContextMenu() |
| | 105 | | { |
| 0 | 106 | | placeCopyContextualMenu.Show(); |
| 0 | 107 | | } |
| | 108 | |
|
| | 109 | | private void OnOpenTwitter() |
| | 110 | | { |
| 0 | 111 | | OnPressedTwitterButton?.Invoke(location, sceneInfo.name); |
| 0 | 112 | | } |
| | 113 | |
|
| | 114 | | private void OnLinkCopied() |
| | 115 | | { |
| 0 | 116 | | OnPressedLinkCopy?.Invoke(location); |
| 0 | 117 | | } |
| | 118 | |
|
| | 119 | | private void Start() |
| | 120 | | { |
| 1 | 121 | | gameObject.SetActive(false); |
| 1 | 122 | | goToButton.onClick.AddListener(OnGotoClick); |
| 1 | 123 | | } |
| | 124 | |
|
| | 125 | | private void OnDestroy() |
| | 126 | | { |
| 1 | 127 | | if (texturePromise != null) |
| | 128 | | { |
| 0 | 129 | | AssetPromiseKeeper_Texture.i.Forget(texturePromise); |
| 0 | 130 | | texturePromise = null; |
| | 131 | | } |
| 1 | 132 | | if(upvoteButton != null) |
| 1 | 133 | | upvoteButton.onClick.RemoveAllListeners(); |
| | 134 | |
|
| 1 | 135 | | if(downvoteButton != null) |
| 1 | 136 | | downvoteButton.onClick.RemoveAllListeners(); |
| 1 | 137 | | } |
| | 138 | |
|
| | 139 | | public void Populate(Vector2Int coordinates, Vector2 worldPosition, MinimapMetadata.MinimapSceneInfo sceneInfo) |
| | 140 | | { |
| 1 | 141 | | if (!gameObject.activeSelf) |
| 1 | 142 | | AudioScriptableObjects.dialogOpen.Play(true); |
| | 143 | |
|
| 1 | 144 | | this.sceneInfo = sceneInfo; |
| 1 | 145 | | bool sceneInfoExists = sceneInfo != null; |
| | 146 | |
|
| 1 | 147 | | gameObject.SetActive(true); |
| 1 | 148 | | scenePreviewImage.gameObject.SetActive(false); |
| 1 | 149 | | location = coordinates; |
| | 150 | |
|
| 1 | 151 | | PositionToast(worldPosition); |
| | 152 | |
|
| 1 | 153 | | sceneLocationText.text = $"{coordinates.x}, {coordinates.y}"; |
| | 154 | |
|
| 1 | 155 | | sceneOwnerText.transform.parent.gameObject.SetActive(sceneInfoExists && !string.IsNullOrEmpty(sceneInfo.owne |
| 1 | 156 | | sceneTitleText.text = "Untitled Scene"; |
| | 157 | |
|
| 1 | 158 | | bool useDefaultThumbnail = |
| | 159 | | !sceneInfoExists || string.IsNullOrEmpty(sceneInfo.previewImageUrl); |
| | 160 | |
|
| 1 | 161 | | if (useDefaultThumbnail) |
| | 162 | | { |
| 1 | 163 | | DisplayThumbnail(scenePreviewFailImage.texture); |
| 1 | 164 | | currentImageUrl = ""; |
| | 165 | | } |
| | 166 | |
|
| 1 | 167 | | if (sceneInfoExists) |
| | 168 | | { |
| 1 | 169 | | sceneTitleText.text = sceneInfo.name; |
| 1 | 170 | | sceneOwnerText.text = $"Created by: {sceneInfo.owner}"; |
| | 171 | |
|
| 1 | 172 | | if (currentImageUrl == sceneInfo.previewImageUrl) |
| | 173 | | { |
| 0 | 174 | | DisplayThumbnail(texturePromise?.asset?.texture); |
| 0 | 175 | | return; |
| | 176 | | } |
| | 177 | |
|
| 1 | 178 | | if (texturePromise != null) |
| | 179 | | { |
| 0 | 180 | | AssetPromiseKeeper_Texture.i.Forget(texturePromise); |
| 0 | 181 | | texturePromise = null; |
| | 182 | | } |
| | 183 | |
|
| 1 | 184 | | if (!string.IsNullOrEmpty(sceneInfo.previewImageUrl)) |
| | 185 | | { |
| 0 | 186 | | texturePromise = new AssetPromise_Texture(sceneInfo.previewImageUrl, storeTexAsNonReadable: false); |
| 0 | 187 | | texturePromise.OnSuccessEvent += (textureAsset) => { DisplayThumbnail(textureAsset.texture); }; |
| 0 | 188 | | texturePromise.OnFailEvent += (textureAsset, error) => { DisplayThumbnail(scenePreviewFailImage.text |
| 0 | 189 | | AssetPromiseKeeper_Texture.i.Keep(texturePromise); |
| | 190 | | } |
| | 191 | |
|
| 1 | 192 | | currentImageUrl = sceneInfoExists ? sceneInfo.previewImageUrl : ""; |
| | 193 | | } |
| 1 | 194 | | } |
| | 195 | |
|
| | 196 | | private void PositionToast(Vector2 worldPosition) |
| | 197 | | { |
| 1 | 198 | | if (toastContainer == null || rectTransform == null) |
| 0 | 199 | | return; |
| | 200 | |
|
| 1 | 201 | | toastContainer.position = worldPosition; |
| | 202 | |
|
| 1 | 203 | | bool useBottom = toastContainer.localPosition.y > 0; |
| | 204 | |
|
| 1 | 205 | | bool shouldOffsetHorizontally = Mathf.Abs(toastContainer.localPosition.x) > rectTransform.rect.width / 4; |
| 1 | 206 | | bool useLeft = false; |
| | 207 | |
|
| 1 | 208 | | if (shouldOffsetHorizontally) |
| 1 | 209 | | useLeft = toastContainer.localPosition.x > 0; |
| | 210 | |
|
| | 211 | | // By setting the pivot accordingly BEFORE we position the toast, we can have it always visible in an easier |
| 1 | 212 | | toastContainer.pivot = new Vector2(shouldOffsetHorizontally ? (useLeft ? 1 : 0) : 0.5f, useBottom ? 1 : 0); |
| 1 | 213 | | toastContainer.position = worldPosition; |
| 1 | 214 | | } |
| | 215 | |
|
| | 216 | | public void SetPlaceId(string UUID) |
| | 217 | | { |
| 0 | 218 | | placeId = UUID; |
| 0 | 219 | | } |
| | 220 | |
|
| | 221 | | public void SetVoteButtons(bool isUpvoted, bool isDownvoted) |
| | 222 | | { |
| 0 | 223 | | placeIsUpvote = isUpvoted; |
| 0 | 224 | | placeIsDownvote = isDownvoted; |
| 0 | 225 | | upvoteOn.SetActive(isUpvoted); |
| 0 | 226 | | upvoteOff.SetActive(!isUpvoted); |
| 0 | 227 | | downvoteOn.SetActive(isDownvoted); |
| 0 | 228 | | downvoteOff.SetActive(!isDownvoted); |
| 0 | 229 | | } |
| | 230 | |
|
| | 231 | | private void ChangeVote(bool upvote) |
| | 232 | | { |
| 0 | 233 | | if (upvote) |
| | 234 | | { |
| 0 | 235 | | OnVoteChanged?.Invoke(placeId, placeIsUpvote ? (bool?)null : true); |
| 0 | 236 | | placeIsUpvote = !placeIsUpvote; |
| 0 | 237 | | placeIsDownvote = false; |
| | 238 | | } |
| | 239 | | else |
| | 240 | | { |
| 0 | 241 | | OnVoteChanged?.Invoke(placeId, placeIsDownvote ? (bool?)null : false); |
| 0 | 242 | | placeIsUpvote = false; |
| 0 | 243 | | placeIsDownvote = !placeIsDownvote; |
| | 244 | | } |
| 0 | 245 | | SetVoteButtons(placeIsUpvote, placeIsDownvote); |
| 0 | 246 | | } |
| | 247 | |
|
| | 248 | | public void Close() |
| | 249 | | { |
| 1 | 250 | | if (gameObject.activeSelf) |
| 1 | 251 | | AudioScriptableObjects.dialogClose.Play(true); |
| | 252 | |
|
| 1 | 253 | | gameObject.SetActive(false); |
| 1 | 254 | | } |
| | 255 | |
|
| | 256 | | private void OnGotoClick() |
| | 257 | | { |
| 0 | 258 | | OnGoto?.Invoke(location.x, location.y); |
| 0 | 259 | | Close(); |
| 0 | 260 | | } |
| | 261 | |
|
| | 262 | | private void DisplayThumbnail(Texture2D texture) |
| | 263 | | { |
| 1 | 264 | | scenePreviewImage.texture = texture; |
| 1 | 265 | | toastAnimator.SetTrigger(triggerLoadingComplete); |
| 1 | 266 | | } |
| | 267 | |
|
| | 268 | | public void SetFavoriteLoading(bool isLoading) |
| | 269 | | { |
| 0 | 270 | | favoriteLoading.SetActive(isLoading); |
| 0 | 271 | | } |
| | 272 | |
|
| | 273 | | public void SetCurrentFavoriteStatus(string uuid, bool isFavorite) |
| | 274 | | { |
| 0 | 275 | | favoriteToggle.Configure(new FavoriteButtonComponentModel() |
| | 276 | | { |
| | 277 | | placeUUID = uuid, |
| | 278 | | isFavorite = isFavorite |
| | 279 | | }); |
| 0 | 280 | | } |
| | 281 | |
|
| | 282 | | public void SetIsAPlace(bool isAPlace) |
| | 283 | | { |
| 0 | 284 | | favoriteToggle.SetInteractable(isAPlace); |
| 0 | 285 | | favoriteButtonImage.sprite = isAPlace ? normalFavorite : blockedFavorite; |
| 0 | 286 | | favoriteButtonImage.color = isAPlace ? normalImageColor : disabledImageColor; |
| 0 | 287 | | SetInfoButtonEnabled(isAPlace); |
| | 288 | |
|
| 0 | 289 | | if(!isAPlace) |
| 0 | 290 | | favoriteLoading.SetActive(false); |
| 0 | 291 | | } |
| | 292 | |
|
| | 293 | | public void SetInfoButtonEnabled(bool isActive) |
| | 294 | | { |
| 0 | 295 | | infoButton.interactable = isActive; |
| 0 | 296 | | infoButtonImage.color = isActive ? normalImageColor : disabledImageColor; |
| 0 | 297 | | } |
| | 298 | |
|
| | 299 | | public void SetPlayerCount(int players) |
| | 300 | | { |
| 0 | 301 | | numberOfUsersContainer.gameObject.SetActive(players > 0); |
| 0 | 302 | | playerCountText.text = players.ToString(); |
| 0 | 303 | | } |
| | 304 | |
|
| | 305 | | public void SetUserVisits(int userVisitsCount) |
| | 306 | | { |
| 0 | 307 | | userVisitsText.text = userVisitsCount.ToString(); |
| 0 | 308 | | } |
| | 309 | |
|
| | 310 | | public void SetUserRating(float? userRatingCount) |
| | 311 | | { |
| 0 | 312 | | userRatingText.text = userRatingCount != null ? $"{userRatingCount.Value * 100:0}%" : "-%"; |
| 0 | 313 | | } |
| | 314 | |
|
| | 315 | | public void RebuildLayouts() |
| | 316 | | { |
| 0 | 317 | | if (numberOfUsersContainer != null) |
| 0 | 318 | | Utils.ForceRebuildLayoutImmediate(numberOfUsersContainer); |
| | 319 | |
|
| 0 | 320 | | if (userVisitsAndRatingContainer != null) |
| 0 | 321 | | Utils.ForceRebuildLayoutImmediate(userVisitsAndRatingContainer); |
| 0 | 322 | | } |
| | 323 | | } |
| | 324 | | } |