/* * Copyright (c) 2006-2017 DMDirc Developers * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package com.dmdirc.ui.messages; import com.dmdirc.config.binding.ConfigBinding; import com.dmdirc.events.BaseChannelTextEvent; import com.dmdirc.events.BaseQueryTextEvent; import com.dmdirc.events.ChannelHighlightEvent; import com.dmdirc.events.DisplayProperty; import com.dmdirc.events.DisplayableEvent; import com.dmdirc.events.QueryHighlightEvent; import com.dmdirc.events.UnreadStatusChangedEvent; import com.dmdirc.events.eventbus.EventBus; import com.dmdirc.interfaces.WindowModel; import com.dmdirc.util.colours.Colour; import java.util.Optional; import java.util.concurrent.TimeUnit; import io.reactivex.Emitter; import io.reactivex.Observable; import io.reactivex.ObservableEmitter; import io.reactivex.Observer; import io.reactivex.functions.Consumer; import io.reactivex.subjects.PublishSubject; import io.reactivex.subjects.ReplaySubject; import io.reactivex.subjects.Subject; import net.engio.mbassy.listener.Handler; import org.reactivestreams.Publisher; /** * Tracks unread messages and other notifications. */ public class UnreadStatusManagerImpl implements UnreadStatusManager { private final WindowModel container; private final ColourManager colourManager; private final Subject eventSubject; private int unreadLines; private Optional notificationColour = Optional.empty(); private Optional miscellaneousColour = Optional.of(Colour.GREEN); private Optional messageColour = Optional.of(Colour.BLUE); private Optional highlightColour = Optional.of(Colour.RED); public UnreadStatusManagerImpl(final WindowModel container) { this.container = container; this.colourManager = new ColourManagerImpl(container.getConfigManager()); this.eventSubject = PublishSubject.create(); eventSubject .throttleLast(200, TimeUnit.MILLISECONDS) .subscribe(unreadStatusChangedEvent -> container.getEventBus().publish(unreadStatusChangedEvent)); } @Handler public void handleDisplayableEvent(final DisplayableEvent event) { if (includeEvent(event)) { updateStatus(miscellaneousColour, unreadLines + 1); } } @Handler public void handleChannelTextEvent(final BaseChannelTextEvent event) { if (includeEvent(event)) { updateStatus(messageColour); } } @Handler public void handleQueryTextEvent(final BaseQueryTextEvent event) { if (includeEvent(event)) { updateStatus(messageColour); } } @Handler public void handleChannelHighlightEvent(final ChannelHighlightEvent event) { if (includeEvent(event)) { updateStatus(highlightColour); } } @Handler public void handleQueryHighlightEvent(final QueryHighlightEvent event) { if (includeEvent(event)) { updateStatus(highlightColour); } } private boolean includeEvent(final DisplayableEvent event) { return event.getSource().equals(container) && !event.getDisplayProperty(DisplayProperty.DO_NOT_DISPLAY).orElse(false); } @Override public int getUnreadLines() { return unreadLines; } @Override public Optional getNotificationColour() { return notificationColour; } @Override public void clearStatus() { updateStatus(Optional.empty(), 0); } private void updateStatus(final Optional desiredColour) { updateStatus(desiredColour, unreadLines); } private void updateStatus(final Optional desiredColour, final int newUnreadCount) { final Optional newColour = getBestColour(desiredColour, notificationColour); final boolean updated = !newColour.equals(notificationColour) || newUnreadCount != unreadLines; notificationColour = newColour; unreadLines = newUnreadCount; if (updated) { publishChangedEvent(); } } private Optional getBestColour( final Optional desiredColour, final Optional existingColour) { if (!desiredColour.isPresent()) { // If we're trying to explicitly reset, go with the empty one. return desiredColour; } if (desiredColour.equals(highlightColour) || !existingColour.isPresent() || existingColour.equals(miscellaneousColour)) { return desiredColour; } else { return existingColour; } } @ConfigBinding(domain = "ui", key = "miscellaneousNotificationColour") void handleMiscellaneousColour(final String colour) { final Optional newColour = Optional.ofNullable( colourManager.getColourFromString(colour, Colour.GREEN)); if (notificationColour.equals(miscellaneousColour)) { notificationColour = newColour; publishChangedEvent(); } miscellaneousColour = newColour; } @ConfigBinding(domain = "ui", key = "messageNotificationColour") void handleMessageColour(final String colour) { final Optional newColour = Optional.ofNullable( colourManager.getColourFromString(colour, Colour.BLUE)); if (notificationColour.equals(messageColour)) { notificationColour = newColour; publishChangedEvent(); } messageColour = newColour; } @ConfigBinding(domain = "ui", key = "highlightNotificationColour") void handleHighlightColour(final String colour) { final Optional newColour = Optional.ofNullable( colourManager.getColourFromString(colour, Colour.RED)); if (notificationColour.equals(highlightColour)) { notificationColour = newColour; publishChangedEvent(); } highlightColour = newColour; } private void publishChangedEvent() { eventSubject.onNext(new UnreadStatusChangedEvent(container, this, notificationColour, unreadLines)); } }