/** * Copyright 2019 The Knights Of Unity, created by Piotr Stoch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using UnityEngine; using UnityEngine.UI; using Nakama; using DemoGame.Scripts.Menus; using DemoGame.Scripts.Chat; using DemoGame.Scripts.Session; namespace DemoGame.Scripts.Friends { public class FriendsListUI : Menu { [Space] /// /// Prefab of friend panel which is instantiated when refreshing list /// [SerializeField] private GameObject _friendPanelPrefab = null; /// /// Reference of scrollRect for changing its content basing on currently selected tab /// [SerializeField] private ScrollRect _scrollRect = null; /// /// Button used for manual refreshing list /// [SerializeField] private Button _refreshButton = null; /// /// Button used for sending friend invitates to users /// [SerializeField] private Button _addFriendButton = null; /// /// Reference to chatChannelUI object for starting chat with user /// [SerializeField] private ChatChannelUI _chatChannelUI = null; [SerializeField] private UsernameSearcher _usernameSearcher = null; [Header("Tabs buttons")] [SerializeField] private Button _friendsTabButton = null; [SerializeField] private Button _sentInvitesTabButton = null; [SerializeField] private Button _receivedInvitesTabButton = null; [SerializeField] private Button _bannedUsersTabButton = null; [Header("Content panels")] [SerializeField] private RectTransform _friendsContent = null; [SerializeField] private RectTransform _sentInvitesContent = null; [SerializeField] private RectTransform _receivedInvitesContent = null; [SerializeField] private RectTransform _bannedUsersContent = null; /// /// Content of currently selected tab /// private RectTransform _currentTabContent; /// /// Button for currently selected tab /// private Button _currentTabButton; /// /// Currently selected friend panel /// private FriendPanel _selectedFriendPanel; #region Mono private void Awake() { //Checking if nakama session manager is connected to server if (NakamaSessionManager.Instance.IsConnected) { //if is - inintializing friends list Init(); } else { //if not - plugging to event OnConnectionSuccess initializing of friends list NakamaSessionManager.Instance.OnConnectionSuccess += Init; } SetBackButtonHandler(MenuManager.Instance.HideTopMenu); //selecting friends tab automatically FriendsTabButtonClicked(); //connecting methods to button clicks _friendsTabButton.onClick.AddListener(FriendsTabButtonClicked); _sentInvitesTabButton.onClick.AddListener(SentInvitesTabButtonClicked); _receivedInvitesTabButton.onClick.AddListener(ReceivedInvitesTabButtonClicked); _bannedUsersTabButton.onClick.AddListener(BannedUsersTabButtonClicked); } #endregion #region private methods /// /// Initializes friends view /// /// /// private async void Init() { Client client = NakamaSessionManager.Instance.Client; ISession session = NakamaSessionManager.Instance.Session; //loading friends data IApiFriends friends = await FriendsManager.LoadFriendsAsync(client, session); if (friends != null) { //refreshing ui view with downloaded data RefreshFriendsListUI(friends); NakamaSessionManager.Instance.OnConnectionSuccess -= Init; } //connecting events that need server connection _addFriendButton.onClick.AddListener(AddFriend); _usernameSearcher.OnSubmit += AddFriend; _refreshButton.onClick.AddListener(ActualizeFriendsList); } /// /// Populating friend list with elements created basing on loaded friends list from database /// private void RefreshFriendsListUI(IApiFriends friends) { ClearLists(); foreach (IApiFriend friend in friends.Friends) { RectTransform content; //selecting to which tab should friend panel be instantiated switch (friend.State) { // Users are friends with each other. case 0: content = _friendsContent; break; // This user has sent an invitation and pending acceptance from other user. case 1: content = _sentInvitesContent; break; // This user has received an invitation but has not accepted yet. case 2: content = _receivedInvitesContent; break; // This user has banned other user. case 3: content = _bannedUsersContent; break; // If state is none of upper log error default: Debug.LogError("Wrong friend state value: \"" + friend.State + "\" in " + friend.User.Username + "!"); return; } //instantiating friend panel object GameObject panelGO = Instantiate(_friendPanelPrefab, content) as GameObject; FriendPanel panel = panelGO.GetComponent(); if (panel) { //initializing object with FriendList object and friend data panel.Init(friend); panel.OnSelected += SelectedPanelChange; //subscribing to event fired after every successful request to friends list in database panel.OnDataChanged += ActualizeFriendsList; panel.OnChatStartButtonClicked += StartChatWithUser; } else { Debug.LogError("Invalid friend panel prefab!"); Destroy(panelGO); } } } /// /// Loading friends from database and refreshing list /// private async void ActualizeFriendsList() { //loading data from server IApiFriends friends = await FriendsManager.LoadFriendsAsync(NakamaSessionManager.Instance.Client, NakamaSessionManager.Instance.Session); if (friends != null) { //refreshing viev RefreshFriendsListUI(friends); } } /// /// Removing all instantiated panels on all lists /// private void ClearLists() { ClearList(_friendsContent); ClearList(_sentInvitesContent); ClearList(_receivedInvitesContent); ClearList(_bannedUsersContent); } /// /// Removing instantiated friend panels from list /// private void ClearList(RectTransform content) { FriendPanel[] friendPanels = content.GetComponentsInChildren(); for (int i = 0; i < friendPanels.Length; i++) { Destroy(friendPanels[i].gameObject); } } /// /// Sends request for adding friend by using FriendsList.AddFriendByUsernameAsync /// public async void AddFriend() { bool success = await FriendsManager.AddFriendByUsernameAsync(_usernameSearcher.InputFieldValue, NakamaSessionManager.Instance.Client, NakamaSessionManager.Instance.Session); if (success) { Debug.Log("friend added"); ActualizeFriendsList(); } else { Debug.LogWarning("friend adding error"); } } /// /// Used when new friend panel is selected and we need to close old /// /// private void SelectedPanelChange(FriendPanel friendPanel) { if (_selectedFriendPanel == friendPanel) { return; } DeselectCurrentPanel(); _selectedFriendPanel = friendPanel; } private void DeselectCurrentPanel(bool closeOldPanelImmediately = false) { if (_selectedFriendPanel) { _selectedFriendPanel.Deselect(true); } _selectedFriendPanel = null; } private async void StartChatWithUser(string userId, string username) { ChatChannel chatChannel = await ChatManager.Instance.JoinChatWithUserAsync(userId); if (chatChannel != null) { chatChannel.ChannelName = username; _chatChannelUI.SetChatChannel(chatChannel); _chatChannelUI.gameObject.SetActive(true); } else { Debug.LogError("Couldn't start chat with user"); } } #region Tab buttons click handlers private void SelectTab(RectTransform content, Button button) { //return if tab already selected if (_currentTabContent == content) { return; } DeselectCurrentPanel(true); //deselecting current tab if (_currentTabContent) { _currentTabContent.gameObject.SetActive(false); } if (_currentTabButton) { _currentTabButton.interactable = true; } //selecting new tab content.gameObject.SetActive(true); _currentTabContent = content; button.interactable = false; _currentTabButton = button; _scrollRect.content = _currentTabContent; } /// /// Selects friend tab /// private void FriendsTabButtonClicked() { SelectTab(_friendsContent, _friendsTabButton); } /// /// Selects sent invites tab /// private void SentInvitesTabButtonClicked() { SelectTab(_sentInvitesContent, _sentInvitesTabButton); } /// /// Selects received invites tab /// private void ReceivedInvitesTabButtonClicked() { SelectTab(_receivedInvitesContent, _receivedInvitesTabButton); } /// /// Selects banned users tab /// private void BannedUsersTabButtonClicked() { SelectTab(_bannedUsersContent, _bannedUsersTabButton); } #endregion #endregion } }