Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using UnityEngine;
- using System.Collections.Generic;
- using System.Linq;
- using UnityEngine.UI;
- using System;
- using System.Collections;
- using System.IO;
- using System.Text.RegularExpressions;
- using System.Threading;
- using Com.TheFallenGames.OSA.Core;
- using Com.TheFallenGames.OSA.CustomParams;
- using frame8.Logic.Misc.Other.Extensions;
- using JamTracks;
- using MaterialUI;
- using MEC;
- using Sirenix.Utilities;
- using UnityEngine.Events;
- public class JamPacksScrollRectItemsAdapter : OSA<JamPacksParams, JamPacksViewsHolder>
- {
- public UnityEvent OnItemsUpdated;
- private Dictionary<JamPacksViewsHolder, PackButtonModel> vHolders = new Dictionary<JamPacksViewsHolder, PackButtonModel>();
- private Dictionary<PackButtonModel, bool> modelChangeVisualAfterStartWaiting = new Dictionary<PackButtonModel, bool>();
- [SerializeField] private int updateListRate = 3;
- private int frameCount = 0;
- private int _IndexOfCurrentlyExpandedItem;
- private List<Pack> packsStates = new List<Pack>();
- protected override void Start()
- {
- base.Start();
- Init();
- StartMethods();
- }
- private void StartMethods()
- {
- try
- {
- LoadPacksState();
- }
- catch (Exception e)
- {
- if (Debug.isDebugBuild)
- Debug.Log("!!!!!!! ERROR while LoadPacksState " + e.Message);
- }
- _Params.Adapter = this;
- _Params.OnPacksUpdated.AddListener(OnReceivedNewModels);
- _Params.OnSortModels.AddListener(OnSortModels);
- _Params.InitPacks();
- //OnReceivedNewModels(_Params.FilteredPacks.Count);
- RegisterEventsListeners();
- EventManager.TriggerEvent("PacksAdapterIsReady");
- Timing.RunCoroutine(CheckInternetConnection(), Segment.SlowUpdate);
- }
- private void OnApplicationQuit()
- {
- SavePacksState();
- }
- public void SavePacksState()
- {
- packsStates = new List<Pack>(_Params.packsLibrary.packs);
- ES3.Save<List<Pack>>("packsStates", packsStates, CommonSettings.Instance.Es3Settings);
- }
- private void LoadPacksState()
- {
- if (ES3.KeyExists("packsStates", CommonSettings.Instance.Es3Settings))
- {
- packsStates = ES3.Load<List<Pack>>("packsStates", CommonSettings.Instance.Es3Settings);
- foreach (var pack in _Params.packsLibrary.packs)
- {
- Pack packState = packsStates.FirstOrDefault(el => el.id == pack.id);
- if (packState != null)
- {
- pack.aviable = packState.aviable;
- pack.hasPreview = packState.hasPreview;
- pack.included = packState.included;
- pack.showInList = packState.showInList;
- }
- }
- }
- else
- {
- SavePacksState();
- }
- }
- public Dictionary<JamPacksViewsHolder, PackButtonModel> GetVHHolders()
- {
- return vHolders;
- }
- private void RegisterEventsListeners()
- {
- EventManager.StartListening("Packs_ResetAllPacksPlayButtons", _Params.ResetAllPacksPlayButtons);
- EventManager.StartListening("Packs_IncludeAllPacks", _Params.IncludeAllPacks);
- EventManager.StartListening("Packs_ExcludeAllPacks", _Params.ExcludeAllPacks);
- EventManager.StartListening("Playlist_FilterAfterPacksChanges", SavePacksState);
- EventManager.StartListeningCustom("PackPurchased", _Params.OnPackPurchased);
- EventManager.StartListeningCustom("ApplyPacksStyleFilterOptions", _Params.FilterPacksByStyle);
- //EventManager.StartListening("PurchaserInitialized", _Params.ChangePacksPrices);
- }
- /*private bool GetTrackCachedState(string trackName)
- {
- return File.Exists(@GetTrackPathInFilesystem(trackName));
- }
- private string GetTrackPathInFilesystem(string trackName)
- {
- return FileManager.Instance.GetAndroidFriendlyFilesPath() + "/" + trackName.ToLower() + ".mp3";
- }*/
- /*private bool GetTrackCachedState(TrackButtonModel track)
- {
- return File.Exists(@GetTrackPathInFilesystem(track)) && new System.IO.FileInfo(@GetTrackPathInFilesystem(track)).Length == track.fileSize;
- }
- private string GetTrackPathInFilesystem(TrackButtonModel track)
- {
- return FileManager.Instance.GetAndroidFriendlyFilesPath() + "/" + track.clipName.ToLower() + ".mp3";
- }*/
- private IEnumerator<float> CheckInternetConnection()
- {
- while (true)
- {
- if (Application.internetReachability != NetworkReachability.NotReachable)
- {
- _Params.ChangePacksPrices();
- }
- yield return 0f;
- }
- }
- protected override void Update()
- {
- base.Update();
- if (frameCount > (int) (1 / Time.deltaTime / updateListRate))
- {
- foreach (var vh in vHolders)
- {
- if (!modelChangeVisualAfterStartWaiting.ContainsKey(vh.Value))
- {
- modelChangeVisualAfterStartWaiting.Add(vh.Value, false);
- }
- if (vh.Value.previewTrack.waitingLoading)
- {
- if (!modelChangeVisualAfterStartWaiting[vh.Value])
- {
- modelChangeVisualAfterStartWaiting[vh.Value] = true;
- vh.Key.ChangeElementLoadingState(vh.Value);
- }
- continue;
- }
- if (vh.Value.previewTrack.loading)
- {
- vh.Key.progressBar.SetProgress(vh.Value.previewTrack.loadingValue, false);
- modelChangeVisualAfterStartWaiting[vh.Value] = false;
- vh.Key.ChangeElementLoadingState(vh.Value);
- continue;
- }
- if (!vh.Value.previewTrack.loading && vh.Value.previewTrack.loaded || (!vh.Value.previewTrack.loading && !vh.Value.previewTrack.loaded && !vh.Value.previewTrack.waitingLoading))
- {
- vh.Key.ChangeElementLoadingState(vh.Value);
- vh.Key.SetPlayButtonIcon(vh.Value);
- }
- if (_Params.PricesIninitilized)
- {
- vh.Key.ChangePacksPriceString(vh.Value);
- vh.Key.ChangePacksPackMenuState(vh.Value);
- }
- }
- frameCount = 0;
- }
- frameCount++;
- foreach (var vh in vHolders)
- {
- vh.Key.progressBar.transform.position = vh.Key.progressBarTMP.transform.position;
- vh.Key.ChangePacksDescButtonRotation(vh.Value);
- vh.Key.ChangeIncludeSwitchVisibility(vh.Value);
- }
- }
- protected override void OnItemHeightChangedPreTwinPass(JamPacksViewsHolder vh)
- {
- base.OnItemHeightChangedPreTwinPass(vh);
- if (_Params.GroupPacks)
- {
- //_Params.flattenedVisibleHierarchy[vh.ItemIndex].HasPendingSizeChange = false;
- /*if (_Params.flattenedVisibleHierarchy[vh.ItemIndex].IsDirectory)
- _Params.flattenedVisibleHierarchy[vh.ItemIndex].HasPendingSizeChange = false;*/
- }
- else
- {
- _Params.Data[vh.ItemIndex].HasPendingSizeChange = false;
- }
- vh.contentSizeFitter.enabled = false;
- }
- /// <inheritdoc/>
- public override void ChangeItemsCount(ItemCountChangeMode changeMode, int itemsCount, int indexIfInsertingOrRemoving = -1, bool contentPanelEndEdgeStationary = false, bool keepVelocity = false)
- {
- _IndexOfCurrentlyExpandedItem = -1; // at initialization, and each time the item count changes, this should be invalidated
- base.ChangeItemsCount(changeMode, itemsCount, indexIfInsertingOrRemoving, contentPanelEndEdgeStationary, keepVelocity);
- }
- PackButtonModel CreateNewModelNode(int itemIndex, int numChildren)
- {
- var m = CreateNewModel(itemIndex, true);
- m.children = new PackButtonModel[numChildren];
- return m;
- }
- PackButtonModel CreateNewModel(int itemId, bool isDirectory)
- {
- TrackButtonModel previewTrack = new TrackButtonModel();
- var filteredPack = _Params.FilteredPacks.Find(el => el.id == itemId);
- if (filteredPack != null)
- {
- previewTrack.clipName = "[" + filteredPack.name.Replace("v.", "v").Replace("'n'", "n").ToLower() + "] preview";
- bool trackCached = FileManager.Instance.GetTrackCachedState(previewTrack);
- previewTrack.loaded = trackCached;
- previewTrack.loading = false;
- previewTrack.waitingLoading = false;
- previewTrack.id = Int32.MaxValue - filteredPack.id;
- }
- Debug.Log($"CreateNewModel itemId = {itemId}");
- return new PackButtonModel()
- {
- id = isDirectory ? -1 : itemId,
- aviable = isDirectory || filteredPack.aviable,
- included = isDirectory || filteredPack.included,
- showInList = isDirectory || filteredPack.showInList,
- hasPreview = !isDirectory && filteredPack.hasPreview,
- title = isDirectory
- ? _Params.PacksGrouped.Keys.ElementAtOrDefault(itemId) != null ? _Params.PacksGrouped.Keys.ElementAtOrDefault(itemId) : ""
- : filteredPack.Title,
- name = isDirectory ? "" : filteredPack.name,
- bg = isDirectory ? null : filteredPack.bg,
- bg_mini = isDirectory ? null : filteredPack.bg_mini,
- price = isDirectory ? 0 : filteredPack.Price,
- priceLocalizedString = isDirectory ? "" : filteredPack.PriceLocalized,
- Description = isDirectory ? "" : filteredPack.Description,
- descExpanded = false,
- previewTrack = isDirectory ? null : previewTrack
- };
- }
- PackButtonModel CreateNewModelNotGrouped(int itemIndex)
- {
- TrackButtonModel previewTrack = new TrackButtonModel();
- previewTrack.clipName = "[" + _Params.FilteredPacks[itemIndex].name.Replace("v.", "v").Replace("'n'", "n").ToLower() + "] preview";
- bool trackCached = FileManager.Instance.GetTrackCachedState(previewTrack);
- previewTrack.loaded = trackCached;
- previewTrack.loading = false;
- previewTrack.waitingLoading = false;
- previewTrack.id = Int32.MaxValue - _Params.FilteredPacks[itemIndex].id;
- return new PackButtonModel()
- {
- id = _Params.FilteredPacks[itemIndex].id,
- aviable = _Params.FilteredPacks[itemIndex].aviable,
- included = _Params.FilteredPacks[itemIndex].included,
- showInList = _Params.FilteredPacks[itemIndex].showInList,
- hasPreview = _Params.FilteredPacks[itemIndex].hasPreview,
- title = _Params.FilteredPacks[itemIndex].Title,
- name = _Params.FilteredPacks[itemIndex].name,
- bg = _Params.FilteredPacks[itemIndex].bg,
- bg_mini = _Params.FilteredPacks[itemIndex].bg_mini,
- price = _Params.FilteredPacks[itemIndex].Price,
- priceLocalizedString = _Params.FilteredPacks[itemIndex].PriceLocalized,
- Description = _Params.FilteredPacks[itemIndex].Description,
- descExpanded = false,
- previewTrack = previewTrack
- };
- }
- public void OnSortModels()
- {
- if (_Params.GroupPacks)
- {
- ResetItems(_Params.flattenedVisibleHierarchy.Count);
- }
- else
- {
- ResetItems(_Params.Data.Count);
- }
- if (gameObject.activeInHierarchy)
- {
- if (!_Params.GroupPacks)
- {
- SmoothScrollTo(0, CommonSettings.Instance.playListScrollToSpeed);
- }
- }
- OnItemsUpdated?.Invoke();
- }
- public async void OnReceivedNewModels(int newCount)
- {
- await OnReceivedNewModelsCoroutine(newCount);
- }
- private IEnumerator OnReceivedNewModelsCoroutine(int newCount)
- {
- if (Debug.isDebugBuild)
- Debug.Log("Packs OnReceivedNewModelsCoroutine newCount = " + newCount);
- yield return null;
- vHolders.Clear();
- var newModels = new PackButtonModel[newCount];
- if (_Params.GroupPacks)
- {
- //_Params.PacksGrouped.Count + 1, потому что добавляем без стиля фришную библу
- //_Params.hierarchyRootNode = CreateNewModelNode(0, _Params.PacksGrouped.Count);
- _Params.hierarchyRootNode = CreateNewModelNode(0, _Params.PacksGrouped.Count);
- int packModelIndex = 0;
- //for (int i = 0; i < _Params.hierarchyRootNode.children.Length - 1; i++)
- for (int i = 0; i < _Params.hierarchyRootNode.children.Length; i++)
- {
- _Params.hierarchyRootNode.children[i] = CreateNewModelNode(i, _Params.PacksGrouped.ElementAt(i).Value.Count);
- int j = 0;
- foreach (var pack in _Params.PacksGrouped.ElementAt(i).Value)
- {
- _Params.hierarchyRootNode.children[i].children[j] = CreateNewModel(pack.id, false);
- j++;
- packModelIndex++;
- }
- }
- //тут добавляем фришную либу c id 1, она идет НЕ как папка
- // /_Params.hierarchyRootNode.children[_Params.hierarchyRootNode.children.Length - 1] = CreateNewModel(1, false);
- _Params.flattenedVisibleHierarchy = new List<PackButtonModel>(_Params.hierarchyRootNode.children);
- newModels = _Params.flattenedVisibleHierarchy.ToArray();
- }
- else
- {
- for (int i = 0; i < newCount; ++i)
- {
- newModels[i] = CreateNewModelNotGrouped(i);
- }
- }
- //yield return null;
- if (!_Params.GroupPacks)
- {
- _Params.Data.Clear();
- _Params.Data.AddRange(newModels);
- }
- //yield return null;
- if (_Params.GroupPacks)
- {
- ResetItems(_Params.flattenedVisibleHierarchy.Count);
- }
- else
- {
- ResetItems(_Params.Data.Count);
- }
- //yield return null;
- if (gameObject.activeInHierarchy)
- {
- SmoothScrollTo(0, CommonSettings.Instance.playListScrollToSpeed);
- }
- OnItemsUpdated?.Invoke();
- }
- protected override JamPacksViewsHolder CreateViewsHolder(int itemIndex)
- {
- var instance = new JamPacksViewsHolder();
- instance.Init(_Params.itemPrefab, itemIndex);
- instance.button.onClick.AddListener(() => OnDirectoryFoldOutClicked(instance));
- if (_Params.GroupPacks)
- {
- if (!_Params.flattenedVisibleHierarchy[instance.ItemIndex].IsDirectory && !vHolders.ContainsKey(instance))
- {
- vHolders.Add(instance, null);
- }
- }
- else if (!vHolders.ContainsKey(instance))
- {
- vHolders.Add(instance, null);
- }
- instance.expandDescButton.onClick.AddListener(() => OnExpandButtonClick(instance));
- return instance;
- }
- private void OnDirectoryFoldOutClicked(JamPacksViewsHolder vh)
- {
- if (!_Params.GroupPacks)
- return;
- var model = _Params.flattenedVisibleHierarchy[vh.ItemIndex];
- if (model.IsDirectory)
- {
- if (Debug.isDebugBuild)
- Debug.Log($"OnDirectoryFoldOutClicked model.children.Length = {model.children.Length}");
- bool wasExpanded = model.expanded;
- model.expanded = !model.expanded;
- int nextIndex = vh.ItemIndex + 1;
- if (wasExpanded)
- {
- int i = vh.ItemIndex + 1 + model.children.Length;
- int countToRemove = i - nextIndex;
- if (countToRemove > 0)
- {
- _Params.flattenedVisibleHierarchy.RemoveRange(nextIndex, countToRemove);
- RemoveItems(nextIndex, countToRemove);
- vHolders.Clear();
- }
- }
- else
- {
- if (model.children.Length > 0)
- {
- _Params.flattenedVisibleHierarchy.InsertRange(nextIndex, model.children);
- InsertItems(nextIndex, model.children.Length);
- vHolders.Clear();
- }
- }
- //model.HasPendingSizeChange = true;
- vh.UpdateViews(model, _Params);
- _Params.OnSortModels.Invoke();
- //model.HasPendingSizeChange = true;
- }
- }
- private void OnExpandButtonClick(JamPacksViewsHolder vh)
- {
- PackButtonModel model = null;
- if (_Params.GroupPacks)
- {
- model = _Params.flattenedVisibleHierarchy[vh.ItemIndex];
- }
- else
- {
- model = _Params.Data[vh.ItemIndex];
- }
- model.descExpanded = !model.descExpanded;
- // No need to set HasPendingSizeChange=true, since the rectTransform will be updated immediately
- vh.UpdateExpandedState(model.descExpanded);
- // If you're enabling/disabling children that can have an impact on the item's size (as opposed to just changing their content - like the Text.text property),
- // this is he only reliable way of dynamically changing an item's size through SRIA v3.2 or lower.
- // The size changed. Enable the CSF component
- // This is not needed here in the current case (replace it with vh.contentSizeFitter.enabled=true if you want),
- // since we're using the "ForceXXX" version of the layout rebuilding function,
- // but we should do it in general, in case your viewholder has some own logic to be executed right before a rebuild event.
- vh.MarkForRebuild();
- // The CSF component will resize the root accordingly
- // Use Canvas.ForceUpdateCanvases() instead, if on old unity version
- LayoutRebuilder.ForceRebuildLayoutImmediate(vh.root);
- // The CSF component was used to estimate the item's size, but the adapter itself
- // should set it (along with correctly setting the item's position, shifting other items, updating sizes cache etc.)
- RequestChangeItemSizeAndUpdateLayout(vh, vh.root.rect.height);
- // MarkForRebuild has set it to true; We used it, now set it back to false - not too important,
- // because it'll be disabled anyway next time it's recycled, but it's nice to clean after ourselves:)
- vh.contentSizeFitter.enabled = false;
- if (model.descExpanded)
- {
- //SmoothScrollTo(vh.ItemIndex, 0.2f);
- }
- }
- protected override void UpdateViewsHolder(JamPacksViewsHolder newOrRecycled)
- {
- PackButtonModel model = null;
- if (_Params.GroupPacks)
- {
- if (!_Params.flattenedVisibleHierarchy[newOrRecycled.ItemIndex].IsDirectory)
- {
- if (vHolders.ContainsKey(newOrRecycled))
- {
- vHolders[newOrRecycled] = _Params.flattenedVisibleHierarchy[newOrRecycled.ItemIndex];
- }
- else
- {
- vHolders.Add(newOrRecycled, _Params.flattenedVisibleHierarchy[newOrRecycled.ItemIndex]);
- }
- }
- model = _Params.flattenedVisibleHierarchy[newOrRecycled.ItemIndex];
- }
- else
- {
- if (vHolders.ContainsKey(newOrRecycled))
- {
- vHolders[newOrRecycled] = _Params.Data[newOrRecycled.ItemIndex];
- }
- else
- {
- vHolders.Add(newOrRecycled, _Params.Data[newOrRecycled.ItemIndex]);
- }
- model = _Params.Data[newOrRecycled.ItemIndex];
- }
- newOrRecycled.UpdateViews(model, _Params);
- if (newOrRecycled.contentSizeFitter.enabled)
- {
- newOrRecycled.contentSizeFitter.enabled = false;
- }
- if (model != null && model.HasPendingSizeChange)
- {
- // Height will be available before the next 'twin' pass, inside OnItemHeightChangedPreTwinPass() callback (see above)
- newOrRecycled.MarkForRebuild(); // will enable the content size fitter
- ScheduleComputeVisibilityTwinPass();
- }
- }
- protected override void RebuildLayoutDueToScrollViewSizeChange()
- {
- // Invalidate the last sizes so that they'll be re-calculated
- if (_Params.GroupPacks)
- {
- foreach (var model in _Params.flattenedVisibleHierarchy)
- {
- //if (!model.IsDirectory)
- //model.HasPendingSizeChange = true;
- }
- }
- else
- {
- foreach (var model in _Params.Data)
- {
- model.HasPendingSizeChange = true;
- }
- }
- base.RebuildLayoutDueToScrollViewSizeChange();
- }
- }
- public class JamPacksViewsHolder : BaseItemViewsHolder
- {
- public CircularProgressIndicator progressBar;
- public CircularProgressIndicator progressBarTMP;
- public Button expandDescButton;
- public Button buyButton;
- public MaterialSwitch includeSwitch;
- public Transform packDesc;
- public Text packDescText;
- public Transform packDescGO;
- public Button playPreviewButton;
- public VectorImage playPreviewIcon;
- public CanvasGroup playPreviewButtonCanvasGroup;
- public Text packTitle;
- public Image packImage;
- public Text tracksCount;
- public Text timeCount;
- public Text price;
- public Transform packPreviewButtonGO;
- public Transform packPreviewTextGO;
- public RectTransform packDescTextRect;
- public LayoutElement packDescTextLayoutElement;
- public MaterialDropdown packMenu;
- public Button button;
- public Transform dirStateGO;
- public Transform packStateGO;
- public Text dirLabel;
- public VectorImage dirIcon;
- public Text dirCount;
- private Match packMatch = null;
- public PackButtonModel _Model;
- public JamPacksParams _Params;
- public bool changeIncludeSwitchFromVH = true;
- public ContentSizeFitter contentSizeFitter { get; private set; }
- private int maxTracksSimLoading = 5;
- private int currentLoadingCount = 0;
- private ImageData playIcon;
- private ImageData pauseIcon;
- private ImageData dirExpandMoreIcon = null;
- private ImageData dirExpandLessIcon = null;
- public override void CollectViews()
- {
- base.CollectViews();
- contentSizeFitter = root.GetComponent<ContentSizeFitter>();
- /*root.GetComponentAtPath("Desc/PackDesc/Text", out packDescText);
- root.GetComponentAtPath("Desc", out packDescGO);
- root.GetComponentAtPath("Top/Buttons/ExpandButton", out expandDescButton);
- root.GetComponentAtPath("Top/Buttons/BuyButton", out buyButton);
- root.GetComponentAtPath("Top/Buttons/Switch", out includeSwitch);
- root.GetComponentAtPath("Top/TrackPackImg", out packImage);
- root.GetComponentAtPath("Top/Title/Desc/PackPreview/Button/DownloadProgress_Circle", out progressBar);
- root.GetComponentAtPath("Top/Title/Desc/PackPreview/Button", out packPreviewButtonGO);
- root.GetComponentAtPath("Top/Title/Desc/PackPreview/Text", out packPreviewTextGO);
- root.GetComponentAtPath("Top/Title/Desc/PackPreview/Button/DownloadProgress_CircleTMP", out progressBarTMP);
- root.GetComponentAtPath("Top/Title/Desc/PackPreview/Button/PlayIcon", out playPreviewButton);
- root.GetComponentAtPath("Top/Title/Desc/PackPreview/Button/PlayIcon", out playPreviewButtonCanvasGroup);
- root.GetComponentAtPath("Top/Title/Desc/PackPreview/Button/PlayIcon/Icon", out playPreviewIcon);
- root.GetComponentAtPath("Top/Title/Top/Dropdown", out packMenu);
- root.GetComponentAtPath("Top/Title/Top/PackLabel", out packTitle);
- root.GetComponentAtPath("Top/Title/Desc/TracksCount", out tracksCount);
- root.GetComponentAtPath("Top/Title/Desc/TimeCount", out timeCount);
- root.GetComponentAtPath("Top/Title/Desc/Price", out price);
- root.GetComponentAtPath("Desc/PackDesc", out packDesc);
- root.GetComponentAtPath("Desc/PackDesc/Text", out packDescTextLayoutElement);
- root.GetComponentAtPath("Desc/PackDesc/Text", out packDescTextRect);*/
- root.GetComponentAtPath("PackState/Desc/PackDesc/Text", out packDescText);
- root.GetComponentAtPath("PackState/Desc", out packDescGO);
- root.GetComponentAtPath("PackState/Top/Buttons/ExpandButton", out expandDescButton);
- root.GetComponentAtPath("PackState/Top/Buttons/BuyButton", out buyButton);
- root.GetComponentAtPath("PackState/Top/Buttons/Switch", out includeSwitch);
- root.GetComponentAtPath("PackState/Top/TrackPackImg", out packImage);
- root.GetComponentAtPath("PackState/Top/Title/Desc/PackPreview/Button/DownloadProgress_Circle", out progressBar);
- root.GetComponentAtPath("PackState/Top/Title/Desc/PackPreview/Button", out packPreviewButtonGO);
- root.GetComponentAtPath("PackState/Top/Title/Desc/PackPreview/Text", out packPreviewTextGO);
- root.GetComponentAtPath("PackState/Top/Title/Desc/PackPreview/Button/DownloadProgress_CircleTMP", out progressBarTMP);
- root.GetComponentAtPath("PackState/Top/Title/Desc/PackPreview/Button/PlayIcon", out playPreviewButton);
- root.GetComponentAtPath("PackState/Top/Title/Desc/PackPreview/Button/PlayIcon", out playPreviewButtonCanvasGroup);
- root.GetComponentAtPath("PackState/Top/Title/Desc/PackPreview/Button/PlayIcon/Icon", out playPreviewIcon);
- root.GetComponentAtPath("PackState/Top/Title/Top/Dropdown", out packMenu);
- root.GetComponentAtPath("PackState/Top/Title/Top/PackLabel", out packTitle);
- root.GetComponentAtPath("PackState/Top/Title/Desc/TracksCount", out tracksCount);
- root.GetComponentAtPath("PackState/Top/Title/Desc/TimeCount", out timeCount);
- root.GetComponentAtPath("PackState/Top/Title/Desc/Price", out price);
- root.GetComponentAtPath("PackState/Desc/PackDesc", out packDesc);
- root.GetComponentAtPath("PackState/Desc/PackDesc/Text", out packDescTextLayoutElement);
- root.GetComponentAtPath("PackState/Desc/PackDesc/Text", out packDescTextRect);
- root.GetComponentAtPath("DirState", out dirStateGO);
- root.GetComponentAtPath("DirState/DirLabel", out dirLabel);
- root.GetComponentAtPath("DirState/Icon", out dirIcon);
- root.GetComponentAtPath("DirState/Count", out dirCount);
- root.GetComponentAtPath("PackState", out packStateGO);
- /*root.GetComponentAtPath("Top/Buttons/ExpandButton", out expandDescButton);
- root.GetComponentAtPath("Top/Buttons/BuyButton", out buyButton);
- root.GetComponentAtPath("Top/Buttons/Switch", out includeSwitch);
- root.GetComponentAtPath("Top/TrackPackImg", out packImage);
- root.GetComponentAtPath("Top/PackPreview/Button/DownloadProgress_Circle", out progressBar);
- root.GetComponentAtPath("Top/PackPreview/Button", out packPreviewButtonGO);
- root.GetComponentAtPath("Top/PackPreview/Text", out packPreviewTextGO);
- root.GetComponentAtPath("Top/PackPreview/Button/DownloadProgress_CircleTMP", out progressBarTMP);
- root.GetComponentAtPath("Top/PackPreview/Button/PlayIcon", out playPreviewButton);
- root.GetComponentAtPath("Top/PackPreview/Button/PlayIcon", out playPreviewButtonCanvasGroup);
- root.GetComponentAtPath("Top/PackPreview/Button/PlayIcon/Icon", out playPreviewIcon);
- root.GetComponentAtPath("Top/PackPreview/Dropdown", out packMenu);
- root.GetComponentAtPath("Top/Title/PackLabel", out packTitle);
- root.GetComponentAtPath("Top/Title/Desc/TracksCount", out tracksCount);
- root.GetComponentAtPath("Top/Title/Desc/TimeCount", out timeCount);
- root.GetComponentAtPath("Top/Title/Desc/Price", out price);
- root.GetComponentAtPath("Desc/PackDesc", out packDesc);
- root.GetComponentAtPath("Desc/PackDesc/Text", out packDescTextLayoutElement);
- root.GetComponentAtPath("Desc/PackDesc/Text", out packDescTextRect);*/
- playPreviewButton.onClick.AddListener(OnPlayPreviewButtonClick);
- buyButton.onClick.AddListener(OnBuyButtonClick);
- includeSwitch.toggle.onValueChanged.AddListener(OnIncludeSwitchValueChanged);
- price.text = I2.Loc.LocalizationManager.GetTranslation("Common/price_not_aviable");
- button = root.GetComponent<Button>();
- packMenu.gameObject.SetActive(true);
- for (int i = 0; i < packMenu.optionDataList.options.Count; i++)
- {
- var _i = i;
- packMenu.optionDataList.options[i].onOptionSelected += () => {
- if (_Model == null)
- return;
- EventManager.TriggerEventCustom("PackMenuClicked", new Dictionary<string, string>
- {
- {"menuIndex", _i.ToString()},
- {"packId", _Model.id.ToString()}
- });
- };
- }
- packMenu.gameObject.SetActive(CommonSettings.Instance.Premium);
- playIcon = MaterialIconHelper.GetIcon("play_circle_outline");
- pauseIcon = MaterialIconHelper.GetIcon("pause_circle_outline");
- if (dirExpandMoreIcon == null)
- dirExpandMoreIcon = MaterialIconHelper.GetIcon("expand_more");
- if (dirExpandLessIcon == null)
- dirExpandLessIcon = MaterialIconHelper.GetIcon("expand_less");
- }
- private void OnIncludeSwitchValueChanged(bool isOn)
- {
- if (_Model == null)
- return;
- if (_Params.packsLibrary.packs.Any(el => el.id == _Model.id))
- {
- if (_Model.included != isOn)
- {
- _Params.packsLibrary.packs.Find(el => el.id == _Model.id).included = isOn;
- _Model.included = isOn;
- EventManager.TriggerEvent("Playlist_FilterAfterPacksChanges");
- EventManager.TriggerEventCustom("UpdateFiltersFields", new Dictionary<string, string>
- {
- {"packId", _Model.id.ToString()}
- });
- }
- ChangeIncludeSwitchStatus(isOn);
- }
- }
- private void OnBuyButtonClick()
- {
- if (!CommonSettings.Instance.ConnectedOrDialog())
- return;
- PackProduct packProduct = null;
- packProduct = Purchaser.Instance.NC_Products_Packs.FirstOrDefault(el => el.PackID == _Model.id);
- if (packProduct != null)
- {
- Purchaser.Instance.BuyProductID(packProduct.Name);
- }
- else
- {
- if (Debug.isDebugBuild)
- Debug.Log("!!! ERROR packProduct == null");
- }
- }
- private void OnPlayPreviewButtonClick()
- {
- if (_Model == null)
- return;
- if (progressBar.transform.parent != _Params.content)
- {
- progressBar.transform.SetParent(_Params.content, true);
- }
- _Params.PlayStreamingPreviewTrack(_Model);
- /*if (_Model.previewTrack.loaded)
- {
- _Params.PlayPreviewTrack(_Model);
- }
- else
- {
- _Params.DownloadPreviewTrack(_Model);
- }*/
- }
- public void UpdateExpandedState(bool expanded)
- {
- packDescGO.gameObject.SetActive(expanded);
- }
- public override void MarkForRebuild()
- {
- base.MarkForRebuild();
- if (contentSizeFitter)
- {
- contentSizeFitter.enabled = true;
- }
- }
- public void ChangePacksDescButtonRotation(PackButtonModel model)
- {
- expandDescButton.transform.localRotation = model.descExpanded
- ? Quaternion.Euler(new Vector3(0, 0, 180))
- : Quaternion.Euler(Vector3.zero);
- }
- public void ChangePacksPriceString(PackButtonModel model)
- {
- price.text = model.priceLocalizedString;
- price.gameObject.SetActive(!model.aviable);
- }
- public void ChangePacksPackMenuState(PackButtonModel model)
- {
- packMenu.gameObject.SetActive(CommonSettings.Instance._premium && model.aviable);
- }
- public void ChangeElementLoadingState(PackButtonModel model)
- {
- progressBar.gameObject.SetActive(model.previewTrack.loading || model.previewTrack.waitingLoading);
- playPreviewButtonCanvasGroup.alpha = progressBar.gameObject.activeSelf ? 0 : 1;
- if (model.previewTrack.waitingLoading)
- {
- progressBar.StartIndeterminate();
- }
- }
- public void SetPlayButtonIcon(PackButtonModel model)
- {
- if (!model.hasPreview)
- {
- packPreviewButtonGO.gameObject.SetActive(false);
- packPreviewTextGO.gameObject.SetActive(false);
- return;
- }
- packPreviewButtonGO.gameObject.SetActive(true);
- packPreviewTextGO.gameObject.SetActive(true);
- if (model.previewTrackPlaying)
- {
- playPreviewIcon.SetImage(pauseIcon);
- }
- else
- {
- playPreviewIcon.SetImage(playIcon);
- }
- }
- public void ChangeIncludeSwitchVisibility(PackButtonModel model)
- {
- buyButton.gameObject.SetActive(!model.aviable);
- includeSwitch.gameObject.SetActive(model.aviable);
- }
- public void ChangeIncludeSwitchStatus(bool isOn)
- {
- includeSwitch.toggle.isOn = isOn;
- }
- public void UpdateViews(PackButtonModel model, JamPacksParams _params = null)
- {
- if (packStateGO != null)
- packStateGO.gameObject.SetActive(!model.IsDirectory);
- if (dirStateGO != null)
- dirStateGO.gameObject.SetActive(model.IsDirectory);
- if (model.IsDirectory)
- {
- if (model.children != null)
- {
- dirCount.text = model.children.Length.ToString();
- }
- dirLabel.text = $"CATEGORY {model.title.Replace("Indoe rock", "Indie rock")}";
- dirIcon.SetImage(model.expanded
- ? dirExpandLessIcon
- : dirExpandMoreIcon);
- }
- else
- {
- packTitle.text = model.title;
- packDescText.text = model.Description;
- packImage.sprite = model.bg;
- includeSwitch.toggleOnLabel = includeSwitch.toggleOffLabel = I2.Loc.LocalizationManager.GetTranslation("Common/Include_in_playlist");
- if (_params?.packsTracksAmount.Keys.ElementAtOrDefault(model.id) != null)
- {
- tracksCount.text = _params.packsTracksAmount[model.id].ToString() + " " + I2.Loc.LocalizationManager.GetTranslation("Common/Tracks");
- }
- if (_params?.packsTracksDuration.Keys.ElementAtOrDefault(model.id) != null)
- {
- timeCount.text = _params.packsTracksDuration[model.id].ToString() + I2.Loc.LocalizationManager.GetTranslation("Common/m");
- }
- SetPlayButtonIcon(model);
- if (packDescGO.gameObject.activeSelf != model.descExpanded)
- {
- UpdateExpandedState(model.descExpanded);
- model.HasPendingSizeChange = true;
- }
- progressBar.transform.position = progressBarTMP.transform.position;
- ChangeElementLoadingState(model);
- ChangeIncludeSwitchVisibility(model);
- ChangeIncludeSwitchStatus(model.included);
- }
- _Model = model;
- _Params = _params;
- }
- }
- public class PackButtonModel
- {
- public int id;
- public bool aviable;
- public bool hasPreview;
- public string title;
- public string name;
- public Sprite bg;
- public Sprite bg_mini;
- public float price;
- public string priceLocalizedString;
- public TrackButtonModel previewTrack;
- public bool previewTrackPlaying = false;
- public bool included;
- public bool showInList;
- private string _description;
- public bool IsDirectory
- {
- get { return children != null; }
- }
- public string Description
- {
- get { return _description; }
- set
- {
- if (_description != value)
- {
- _description = value;
- }
- }
- }
- public bool descExpanded = false;
- public bool HasPendingSizeChange { get; set; }
- public PackButtonModel()
- {
- HasPendingSizeChange = true;
- }
- public PackButtonModel[] children;
- public bool expanded;
- }
- [Serializable]
- public class JamPacksParams : BaseParamsWithPrefabAndData<PackButtonModel>
- {
- public class JamPacksPlaylistUpdateEvent : UnityEvent<int>
- {
- }
- public JamPacksPlaylistUpdateEvent OnPacksUpdated = new JamPacksPlaylistUpdateEvent();
- public UnityEvent OnSortModels = new UnityEvent();
- public TracksLibrary tracksLibrary;
- public PacksLibrary packsLibrary;
- public Dictionary<int, int> packsTracksAmount = new Dictionary<int, int>();
- public Dictionary<int, int> packsTracksDuration = new Dictionary<int, int>();
- public Transform content;
- private string lastPreviewFilename;
- public JamPacksScrollRectItemsAdapter Adapter;
- private bool _pricesIninitilized = false;
- public bool PricesIninitilized
- {
- get { return _pricesIninitilized; }
- set { _pricesIninitilized = value; }
- }
- private List<Pack> _filteredPacks = new List<Pack>();
- public List<Pack> FilteredPacks
- {
- get { return _filteredPacks; }
- }
- public string currentGroupField = "Style";
- public bool GroupPacks = false;
- private Dictionary<string, string> _packsCategories = new Dictionary<string, string>();
- public Dictionary<string, string> PacksCategories
- {
- get { return _packsCategories; }
- }
- private Dictionary<string, List<Pack>> _packsGrouped = new Dictionary<string, List<Pack>>();
- public Dictionary<string, List<Pack>> PacksGrouped
- {
- get { return _packsGrouped; }
- }
- public PackButtonModel hierarchyRootNode;
- public List<PackButtonModel> flattenedVisibleHierarchy = new List<PackButtonModel>();
- public void InitPacks()
- {
- _filteredPacks = new List<Pack>(packsLibrary.packs.Where(el => el.showInList));
- foreach (var pack in packsLibrary.packs)
- {
- int tracksAmount = tracksLibrary.tracks.Where(el => el.pack.ToLower() == pack.name.ToLower()).ToList().Count;
- if (!packsTracksAmount.ContainsKey(pack.id))
- {
- packsTracksAmount.Add(pack.id, tracksAmount);
- }
- }
- foreach (var pack in packsLibrary.packs)
- {
- float packDuration = tracksLibrary.tracks.Where(el => el.pack.ToLower() == pack.name.ToLower()).Sum(el => el.lenght);
- if (!packsTracksDuration.ContainsKey(pack.id))
- {
- packsTracksDuration.Add(pack.id, (int) (packDuration / 60));
- }
- }
- currentGroupField = "Style";
- SetPacksGrouped(currentGroupField);
- }
- public void SetPacksGrouped(string field)
- {
- currentGroupField = field;
- _packsCategories.Clear();
- _packsGrouped.Clear();
- switch (currentGroupField)
- {
- case "Style":
- GroupPacksByStyle();
- break;
- }
- }
- private void GroupPacksByStyle()
- {
- /*Debug.Log("----------");
- foreach (var style in GetPacksStylesFromFiltered())
- {
- Debug.Log(style);
- }
- Debug.Log("----------");
- Debug.Log("----------");
- foreach (var style in AppMenuEventsHandler.Instance.CachedStylesTranslations)
- {
- Debug.Log(style.Key + "|" + style.Value);
- }
- */
- foreach (var style in GetPacksStylesFromFiltered())
- {
- //Debug.Log(style);
- //_tracksCategories.Add(LocalizationManager.GetTranslation("Common/Styles_" + style), style);
- _packsCategories.Add(AppMenuEventsHandler.Instance.CachedStylesTranslations[style.ToLower().Replace(" ", "_").Replace("'", "_")], style);
- }
- foreach (var style in _packsCategories)
- {
- if (_filteredPacks.Any(el => el.Style.ToLower() == style.Value.ToLower()))
- _packsGrouped.Add(style.Key, _filteredPacks.FindAll(el => el.Style.ToLower() == style.Value.ToLower()));
- //Тут у нас все паки кроме бесплатного, потому что у него нет стиля
- }
- Debug.Log("----------");
- foreach (var el in _packsGrouped)
- {
- Debug.Log(el.Key + "|" + el.Value.Count);
- }
- }
- private SortedSet<string> GetPacksStylesFromFiltered()
- {
- SortedSet<string> styles = new SortedSet<string>();
- for (int i = 0; i < _filteredPacks.Count; i++)
- {
- if (_filteredPacks[i].showInList && !_filteredPacks[i].Style.IsNullOrWhitespace())
- {
- styles.Add(_filteredPacks[i].Style);
- }
- }
- return styles;
- }
- private void OnPreviewTrackStartLoading(PackButtonModel model)
- {
- model.previewTrack.loadingValue = 0;
- }
- public void ChangePacksPrices()
- {
- if (_pricesIninitilized)
- return;
- if (!Purchaser.Instance.Initialized)
- return;
- _pricesIninitilized = true;
- foreach (var item in Purchaser.Instance.Controller.products.all)
- {
- PackProduct packProduct = null;
- packProduct = Purchaser.Instance.NC_Products_Packs.Find(el => el.Name == item.definition.id);
- if (packProduct == null)
- continue;
- if (!packsLibrary.packs.Exists(el => el.id == packProduct.PackID))
- continue;
- packsLibrary.packs.Find(el => el.id == packProduct.PackID).Price = (float) item.metadata.localizedPrice;
- packsLibrary.packs.Find(el => el.id == packProduct.PackID).PriceLocalized = item.availableToPurchase
- ? item.metadata.localizedPriceString
- : I2.Loc.LocalizationManager.GetTranslation("Common/product_not_aviable");
- }
- InitPacks();
- OnPacksUpdated.Invoke(_filteredPacks.Count);
- }
- private void OnPreviewTrackLoadingProgress(PackButtonModel model, float progress)
- {
- model.previewTrack.waitingLoading = false;
- model.previewTrack.loaded = false;
- model.previewTrack.loading = true;
- model.previewTrack.loadingValue = progress;
- }
- private void ChangeAllPacksIncludedStatus(bool status)
- {
- for (int i = 0; i < Adapter.GetVHHolders().Values.Count(el => el.aviable); i++)
- {
- if (Adapter.GetVHHolders().Values.ElementAt(i).aviable)
- {
- Adapter.GetVHHolders().Values.ElementAt(i).included = status;
- Adapter.GetVHHolders().Keys.ElementAt(i).includeSwitch.toggle.isOn = status;
- }
- }
- foreach (var packModel in Data.Where(el => el.aviable))
- {
- packModel.included = status;
- }
- foreach (var pack in packsLibrary.packs.Where(el => el.aviable))
- {
- pack.included = status;
- }
- EventManager.TriggerEvent("Playlist_FilterAfterPacksChanges");
- }
- public void IncludeAllPacks()
- {
- ChangeAllPacksIncludedStatus(true);
- }
- public void OnPackPurchased(Dictionary<string, string> paramsDictionary)
- {
- string packIdStr = "-1";
- int packId = -1;
- paramsDictionary.TryGetValue("packId", out packIdStr);
- packId = Int32.Parse(packIdStr);
- if (Debug.isDebugBuild)
- Debug.Log($"OnPackPurchased for {packId}");
- if (packId > 1)
- {
- ChangePackAviableStatus(packId, true);
- }
- }
- private void ChangePackAviableStatus(int packId, bool aviable)
- {
- if (packsLibrary.packs.Exists(el => el.id == packId))
- {
- packsLibrary.packs.Find(el => el.id == packId).aviable = aviable;
- Data.Find(el => el.id == packId).aviable = aviable;
- EventManager.TriggerEvent("Playlist_FilterAfterPacksChanges");
- }
- }
- public void FilterPacksByStyle(Dictionary<string, string> paramsDictionary)
- {
- string selectedOptions = "";
- paramsDictionary.TryGetValue("selectedOptions", out selectedOptions);
- string[] filterOptions = selectedOptions?.Split(new string[] {","}, StringSplitOptions.None);
- if (filterOptions == null)
- return;
- foreach (var pack in packsLibrary.packs)
- {
- pack.showInList = pack.id == 1 || filterOptions.Contains(pack.Style);
- }
- _filteredPacks = packsLibrary.packs.Where(el => el.showInList).ToList();
- OnPacksUpdated.Invoke(_filteredPacks.Count);
- }
- public void ExcludeAllPacks()
- {
- ChangeAllPacksIncludedStatus(false);
- }
- public void ResetAllPacksPlayButtons()
- {
- if (Adapter == null)
- return;
- foreach (var packModel in Adapter.GetVHHolders().Values)
- {
- packModel.previewTrackPlaying = false;
- }
- lastPreviewFilename = String.Empty;
- }
- private async void OnTrackLoaded(PackButtonModel model, string fileName, bool fromCache)
- {
- if (!fromCache)
- {
- UpdateDataCachedState(model);
- }
- else
- {
- bool newPreviewTrack = fileName != lastPreviewFilename;
- ClipPlayer.Instance.PlayPreview(fileName, model.previewTrack, () => {
- ResetAllPacksPlayButtons();
- model.previewTrackPlaying = true;
- lastPreviewFilename = fileName;
- }, () => { model.previewTrackPlaying = !model.previewTrackPlaying; }, newPreviewTrack);
- }
- model.previewTrack.waitingLoading = false;
- model.previewTrack.loading = false;
- model.previewTrack.loaded = true;
- }
- private void OnTrackLoadingError(PackButtonModel model, string errorMsg)
- {
- ToastManager.Show(errorMsg);
- model.previewTrack.waitingLoading = false;
- model.previewTrack.loading = false;
- model.previewTrack.loaded = false;
- }
- private void UpdateDataCachedState(PackButtonModel model)
- {
- if (Data.Exists(el => el.id == model.id))
- {
- Data.Find(el => el.id == model.id).previewTrack.cached = model.previewTrack.cached;
- }
- }
- private void OnStartStreamingPreviewTrackAssetsLoading(TrackButtonModel model)
- {
- model.waitingLoading = true;
- }
- private void OnStreamingPreviewTrackAssetsLoaded(PackButtonModel model)
- {
- bool newPreviewTrack = model.previewTrack.clipName != lastPreviewFilename;
- ClipPlayer.Instance.PlayPreview(null, model.previewTrack, () => {
- ResetAllPacksPlayButtons();
- model.previewTrackPlaying = true;
- lastPreviewFilename = model.previewTrack.clipName;
- }, () => { model.previewTrackPlaying = !model.previewTrackPlaying; }, newPreviewTrack, true);
- model.previewTrack.waitingLoading = false;
- model.previewTrack.loading = false;
- model.previewTrack.loaded = true;
- }
- public void PlayStreamingPreviewTrack(PackButtonModel model)
- {
- if (Application.internetReachability == NetworkReachability.NotReachable)
- {
- OnTrackLoadingError(model, I2.Loc.LocalizationManager.GetTranslation("Errors/NetworkReachability_error"));
- }
- bool newPreviewTrack = model.previewTrack.clipName != lastPreviewFilename;
- if (newPreviewTrack && Application.internetReachability != NetworkReachability.NotReachable)
- {
- model.previewTrack.waitingLoading = true;
- }
- if (Application.internetReachability != NetworkReachability.NotReachable
- || (Application.internetReachability == NetworkReachability.NotReachable && !newPreviewTrack && ClipPlayer.Instance.isPlayingPreview))
- {
- ClipPlayer.Instance.PlayPreview(null, model.previewTrack, () => {
- ResetAllPacksPlayButtons();
- model.previewTrackPlaying = true;
- lastPreviewFilename = model.previewTrack.clipName;
- model.previewTrack.waitingLoading = false;
- model.previewTrack.loading = false;
- model.previewTrack.loaded = true;
- }, () => { model.previewTrackPlaying = !model.previewTrackPlaying; }, newPreviewTrack, true);
- }
- /*TrackLoadingManager.Instance.StartLoadingStreamingTrackAssets(model.previewTrack,
- () => OnStartStreamingPreviewTrackAssetsLoading(model.previewTrack),
- () => { OnStreamingPreviewTrackAssetsLoaded(model); },
- errorMsg => OnTrackLoadingError(model, errorMsg)
- );*/
- }
- public void PlayPreviewTrack(PackButtonModel model)
- {
- TrackLoadingManager.Instance.StartLoadingTrack(model.previewTrack,
- () => OnPreviewTrackStartLoading(model),
- progress => OnPreviewTrackLoadingProgress(model, progress),
- (fileName, fromCache) => { OnTrackLoaded(model, fileName, fromCache); },
- errorMsg => OnTrackLoadingError(model, errorMsg)
- );
- }
- public async void DownloadPreviewTrack(PackButtonModel model)
- {
- if (!model.previewTrack.loaded && !model.previewTrack.loading && !model.previewTrack.waitingLoading)
- {
- model.previewTrack.waitingLoading = true;
- TrackLoadingManager.TrackState trackState = await TrackLoadingManager.Instance.StartLoadingTrack(model.previewTrack,
- () => OnPreviewTrackStartLoading(model),
- progress => OnPreviewTrackLoadingProgress(model, progress),
- (fileName, fromCache) => {
- model.previewTrack.cached = true;
- OnTrackLoaded(model, fileName, fromCache);
- }
- ,
- errorMsg => OnTrackLoadingError(model, errorMsg),
- true
- );
- switch (trackState)
- {
- /*case TrackLoadingManager.TrackState.Loading:
- model.loading = true;
- break;*/
- case TrackLoadingManager.TrackState.WaitingForLoading:
- model.previewTrack.waitingLoading = true;
- break;
- case TrackLoadingManager.TrackState.LoadingError:
- model.previewTrack.waitingLoading = false;
- model.previewTrack.loaded = false;
- model.previewTrack.loading = false;
- break;
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement