friendslist: add option to hide per-friend login notifications

This commit is contained in:
Adam
2021-12-09 18:55:07 -05:00
parent a585253d36
commit 4fe37f978c
6 changed files with 174 additions and 4 deletions

View File

@@ -1276,7 +1276,7 @@ public interface Client extends GameEngine
*
* @return
*/
NameableContainer<Friend> getFriendContainer();
FriendContainer getFriendContainer();
/**
* Retrieve the nameable container containing ignores

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2021, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.api;
/**
* A nameable container of friends
*/
public interface FriendContainer extends NameableContainer<Friend>
{
/**
* Get the recent logins/logouts of friends from the last few seconds
* @return
*/
Deque<PendingLogin> getPendingLogins();
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2021, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.api;
/**
* A pending friend login/out. This is used to suppress world hop notifications
* by buffering the pending logins to try to match a pending logout with a pending
* login and cancel both.
*/
public interface PendingLogin
{
/**
* The name of the player
* @return
*/
String getName();
/**
* The world the player logged into, or 0 if a logout.
* @return
*/
short getWorld();
}

View File

@@ -28,9 +28,11 @@ import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
@ConfigGroup("friendlist")
@ConfigGroup(FriendListConfig.GROUP)
public interface FriendListConfig extends Config
{
String GROUP = "friendlist";
@ConfigItem(
keyName = "showWorldOnLogin",
name = "Show world on login",

View File

@@ -26,30 +26,40 @@
package net.runelite.client.plugins.friendlist;
import com.google.inject.Provides;
import java.time.temporal.ChronoUnit;
import java.util.Iterator;
import javax.inject.Inject;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.ChatMessageType;
import net.runelite.api.ChatPlayer;
import net.runelite.api.Client;
import net.runelite.api.Friend;
import net.runelite.api.Ignore;
import net.runelite.api.MenuAction;
import net.runelite.api.MessageNode;
import net.runelite.api.NameableContainer;
import net.runelite.api.PendingLogin;
import net.runelite.api.ScriptID;
import net.runelite.api.VarPlayer;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.MenuEntryAdded;
import net.runelite.api.events.ScriptPostFired;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.chat.ChatMessageManager;
import net.runelite.client.chat.QueuedMessage;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.task.Schedule;
import net.runelite.client.util.Text;
@PluginDescriptor(
name = "Friend List",
description = "Add extra information to the friend and ignore lists"
)
@Slf4j
public class FriendListPlugin extends Plugin
{
private static final int MAX_FRIENDS_P2P = 400;
@@ -58,12 +68,21 @@ public class FriendListPlugin extends Plugin
private static final int MAX_IGNORES_P2P = 400;
private static final int MAX_IGNORES_F2P = 100;
private static final String HIDE_NOTIFICATIONS = "Hide notifications";
private static final String SHOW_NOTIFICATIONS = "Show notifications";
@Inject
private Client client;
@Inject
private FriendListConfig config;
@Inject
private ConfigManager configManager;
@Inject
private ChatMessageManager chatMessageManager;
@Provides
FriendListConfig getConfig(ConfigManager configManager)
{
@@ -144,6 +163,46 @@ public class FriendListPlugin extends Plugin
}
}
@Subscribe
public void onMenuEntryAdded(MenuEntryAdded event)
{
final int groupId = WidgetInfo.TO_GROUP(event.getActionParam1());
// Look for "Message" on friends list
if (groupId == WidgetInfo.FRIENDS_LIST.getGroupId() && event.getOption().equals("Message"))
{
String friend = Text.toJagexName(Text.removeTags(event.getTarget()));
client.createMenuEntry(-1)
.setOption(isHideNotification(friend) ? SHOW_NOTIFICATIONS : HIDE_NOTIFICATIONS)
.setType(MenuAction.RUNELITE)
.setTarget(event.getTarget()) //Preserve color codes here
.onClick(e ->
{
boolean hidden = isHideNotification(friend);
setHideNotifications(friend, !hidden);
chatMessageManager.queue(QueuedMessage.builder()
.type(ChatMessageType.CONSOLE)
.value("Login notifications for " + friend + " are now " + (hidden ? "shown." : "hidden."))
.build());
});
}
}
@Schedule(period = 5, unit = ChronoUnit.SECONDS)
public void setHideNotifications()
{
for (Iterator<PendingLogin> it = client.getFriendContainer().getPendingLogins().iterator(); it.hasNext(); )
{
PendingLogin pendingLogin = it.next();
if (isHideNotification(Text.toJagexName(pendingLogin.getName())))
{
log.debug("Removing login notification for {}", pendingLogin.getName());
it.remove();
}
}
}
private void setFriendsListTitle(final String title)
{
Widget friendListTitleWidget = client.getWidget(WidgetInfo.FRIEND_CHAT_TITLE);
@@ -173,4 +232,21 @@ public class FriendListPlugin extends Plugin
return null;
}
private void setHideNotifications(String friend, boolean hide)
{
if (hide)
{
configManager.setConfiguration(FriendListConfig.GROUP, "hidenotification_" + friend, true);
}
else
{
configManager.unsetConfiguration(FriendListConfig.GROUP, "hidenotification_" + friend);
}
}
private boolean isHideNotification(String friend)
{
return configManager.getConfiguration(FriendListConfig.GROUP, "hidenotification_" + friend, Boolean.class) == Boolean.TRUE;
}
}

View File

@@ -31,9 +31,11 @@ import com.google.inject.testing.fieldbinder.BoundFieldModule;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.Friend;
import net.runelite.api.FriendContainer;
import net.runelite.api.MessageNode;
import net.runelite.api.NameableContainer;
import net.runelite.api.events.ChatMessage;
import net.runelite.client.chat.ChatMessageManager;
import net.runelite.client.config.ConfigManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -54,6 +56,14 @@ public class FriendListPluginTest
@Bind
private FriendListConfig config;
@Mock
@Bind
private ConfigManager configManager;
@Mock
@Bind
private ChatMessageManager chatMessageManager;
@Inject
private FriendListPlugin friendListPlugin;
@@ -78,7 +88,7 @@ public class FriendListPluginTest
Friend friend = mock(Friend.class);
when(friend.getWorld()).thenReturn(311);
NameableContainer<Friend> friendContainer = mock(NameableContainer.class);
FriendContainer friendContainer = mock(FriendContainer.class);
when(friendContainer.findByName("test\u00a0rsn")).thenReturn(friend);
when(client.getFriendContainer()).thenReturn(friendContainer);