Merge pull request #6348 from Android-X13/update-peer-tags

Refresh all avatars upon setting a peer's tag
This commit is contained in:
Christoph Atteneder 2022-09-21 21:20:57 +02:00 committed by GitHub
commit 5d06b512da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 113 additions and 53 deletions

View File

@ -42,24 +42,21 @@ import javafx.scene.paint.Color;
import javafx.geometry.Point2D;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import javax.annotation.Nullable;
@Slf4j
public class PeerInfoIcon extends Group {
public interface notify {
void avatarTagUpdated();
}
@Setter
private notify callback;
protected Preferences preferences;
protected final String fullAddress;
protected String tooltipText;
@ -68,10 +65,12 @@ public class PeerInfoIcon extends Group {
protected Pane tagPane;
protected Pane numTradesPane;
protected int numTrades = 0;
private final StringProperty tag;
public PeerInfoIcon(NodeAddress nodeAddress, Preferences preferences) {
this.preferences = preferences;
this.fullAddress = nodeAddress != null ? nodeAddress.getFullAddress() : "";
this.tag = new SimpleStringProperty("");
}
protected void createAvatar(Color ringColor) {
@ -184,10 +183,7 @@ public class PeerInfoIcon extends Group {
.position(localToScene(new Point2D(0, 0)))
.onSave(newTag -> {
preferences.setTagForPeer(fullAddress, newTag);
updatePeerInfoIcon();
if (callback != null) {
callback.avatarTagUpdated();
}
tag.set(newTag);
})
.show();
}
@ -205,20 +201,6 @@ public class PeerInfoIcon extends Group {
}
protected void updatePeerInfoIcon() {
String tag;
Map<String, String> peerTagMap = preferences.getPeerTagMap();
if (peerTagMap.containsKey(fullAddress)) {
tag = peerTagMap.get(fullAddress);
final String text = !tag.isEmpty() ? Res.get("peerInfoIcon.tooltip", tooltipText, tag) : tooltipText;
Tooltip.install(this, new Tooltip(text));
} else {
tag = "";
Tooltip.install(this, new Tooltip(tooltipText));
}
if (!tag.isEmpty())
tagLabel.setText(tag.substring(0, 1));
if (numTrades > 0) {
numTradesLabel.setText(numTrades > 99 ? "*" : String.valueOf(numTrades));
@ -229,9 +211,27 @@ public class PeerInfoIcon extends Group {
numTradesLabel.relocate(scaleFactor * 5, scaleFactor * 1);
}
}
numTradesPane.setVisible(numTrades > 0);
tagPane.setVisible(!tag.isEmpty());
refreshTag();
}
protected void refreshTag() {
Map<String, String> peerTagMap = preferences.getPeerTagMap();
if (peerTagMap.containsKey(fullAddress)) {
tag.set(peerTagMap.get(fullAddress));
}
Tooltip.install(this, new Tooltip(!tag.get().isEmpty() ?
Res.get("peerInfoIcon.tooltip", tooltipText, tag.get()) : tooltipText));
if (!tag.get().isEmpty()) {
tagLabel.setText(tag.get().substring(0, 1));
}
tagPane.setVisible(!tag.get().isEmpty());
}
protected StringProperty tagProperty() {
return tag;
}
}

View File

@ -42,8 +42,4 @@ public class PeerInfoIconDispute extends PeerInfoIcon {
addMouseListener(numTrades, null, null, null, preferences, false,
false, accountAge, 0L, null, null, null);
}
public void refreshTag() {
updatePeerInfoIcon();
}
}

View File

@ -0,0 +1,48 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.desktop.components;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import java.util.HashMap;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class PeerInfoIconMap extends HashMap<String, PeerInfoIcon> implements ChangeListener<String> {
@Override
public PeerInfoIcon put(String key, PeerInfoIcon icon) {
icon.tagProperty().addListener(this);
return super.put(key, icon);
}
@Override
public void changed(ObservableValue<? extends String> o, String oldVal, String newVal) {
log.info("Updating avatar tags, the avatar map size is {}", size());
forEach((key, icon) -> {
// We update all avatars, as some could be sharing the same tag.
// We also temporarily remove listeners to prevent firing of
// events while each icon's tagProperty is being reset.
icon.tagProperty().removeListener(this);
icon.refreshTag();
icon.tagProperty().addListener(this);
});
}
}

View File

@ -28,6 +28,7 @@ import bisq.desktop.components.AutocompleteComboBox;
import bisq.desktop.components.ColoredDecimalPlacesWithZerosText;
import bisq.desktop.components.HyperlinkWithIcon;
import bisq.desktop.components.InfoAutoTooltipLabel;
import bisq.desktop.components.PeerInfoIconMap;
import bisq.desktop.components.PeerInfoIconTrading;
import bisq.desktop.components.TitledGroupBg;
import bisq.desktop.main.MainView;
@ -152,6 +153,8 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
private static final int SHOW_ALL = 0;
private Label disabledCreateOfferButtonTooltip;
protected VBox currencyComboBoxContainer;
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
private final PeerInfoIconMap avatarMap = new PeerInfoIconMap();
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, lifecycle
@ -485,6 +488,8 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
model.priceFeedService.updateCounterProperty().removeListener(priceFeedUpdateCounterListener);
currencySelectionSubscriber.unsubscribe();
avatarMap.clear();
}
static class CurrencyStringConverter extends StringConverter<TradeCurrency> {
@ -1278,6 +1283,8 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
model.preferences,
model.accountAgeWitnessService,
useDevPrivilegeKeys);
String key = offer.getId();
avatarMap.put(key, peerInfoIcon);
setGraphic(peerInfoIcon);
} else {
setGraphic(null);

View File

@ -22,6 +22,7 @@ import bisq.desktop.common.view.FxmlView;
import bisq.desktop.components.AutoTooltipButton;
import bisq.desktop.components.AutoTooltipLabel;
import bisq.desktop.components.HyperlinkWithIcon;
import bisq.desktop.components.PeerInfoIconMap;
import bisq.desktop.components.PeerInfoIconTrading;
import bisq.desktop.components.list.FilterBox;
import bisq.desktop.main.overlays.windows.BsqTradeDetailsWindow;
@ -46,7 +47,6 @@ import javafx.fxml.FXML;
import javafx.stage.Stage;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
@ -129,6 +129,8 @@ public class UnconfirmedBsqSwapsView extends ActivatableViewAndModel<VBox, Uncon
private SortedList<UnconfirmedBsqSwapsListItem> sortedList;
private FilteredList<UnconfirmedBsqSwapsListItem> filteredList;
private ChangeListener<Number> widthListener;
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
private final PeerInfoIconMap avatarMap = new PeerInfoIconMap();
@Inject
public UnconfirmedBsqSwapsView(UnconfirmedBsqSwapsViewModel model,
@ -259,6 +261,8 @@ public class UnconfirmedBsqSwapsView extends ActivatableViewAndModel<VBox, Uncon
filterBox.deactivate();
root.widthProperty().removeListener(widthListener);
avatarMap.clear();
}
private static <T extends Comparable<T>> Comparator<UnconfirmedBsqSwapsListItem> nullsFirstComparing(
@ -400,7 +404,7 @@ public class UnconfirmedBsqSwapsView extends ActivatableViewAndModel<VBox, Uncon
int numPastTrades = newItem.getNumPastTrades();
final NodeAddress tradingPeerNodeAddress = bsqSwapTrade.getTradingPeerNodeAddress();
String role = Res.get("peerInfoIcon.tooltip.tradePeer");
Node peerInfoIcon = new PeerInfoIconTrading(tradingPeerNodeAddress,
PeerInfoIconTrading peerInfoIcon = new PeerInfoIconTrading(tradingPeerNodeAddress,
role,
numPastTrades,
privateNotificationManager,
@ -408,6 +412,8 @@ public class UnconfirmedBsqSwapsView extends ActivatableViewAndModel<VBox, Uncon
preferences,
accountAgeWitnessService,
useDevPrivilegeKeys);
String key = bsqSwapTrade.getId();
avatarMap.put(key, peerInfoIcon);
setPadding(new Insets(1, 15, 0, 0));
setGraphic(peerInfoIcon);
} else {

View File

@ -24,6 +24,7 @@ import bisq.desktop.components.AutoTooltipButton;
import bisq.desktop.components.AutoTooltipLabel;
import bisq.desktop.components.AutoTooltipTableColumn;
import bisq.desktop.components.HyperlinkWithIcon;
import bisq.desktop.components.PeerInfoIconMap;
import bisq.desktop.components.PeerInfoIconTrading;
import bisq.desktop.components.list.FilterBox;
import bisq.desktop.main.overlays.popups.Popup;
@ -63,7 +64,6 @@ import javafx.fxml.FXML;
import javafx.stage.Stage;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
@ -158,6 +158,8 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
private SortedList<ClosedTradesListItem> sortedList;
private FilteredList<ClosedTradesListItem> filteredList;
private ChangeListener<Number> widthListener;
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
private final PeerInfoIconMap avatarMap = new PeerInfoIconMap();
@Inject
public ClosedTradesView(ClosedTradesViewModel model,
@ -344,6 +346,8 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
filterBox.deactivate();
root.widthProperty().removeListener(widthListener);
avatarMap.clear();
}
private static <T extends Comparable<T>> Comparator<ClosedTradesListItem> nullsFirstComparing(Function<ClosedTradesListItem, T> keyExtractor) {
@ -528,7 +532,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
int numPastTrades = item.getNumPastTrades();
NodeAddress tradingPeerNodeAddress = tradeModel.getTradingPeerNodeAddress();
String role = Res.get("peerInfoIcon.tooltip.tradePeer");
Node peerInfoIcon = new PeerInfoIconTrading(tradingPeerNodeAddress,
PeerInfoIconTrading peerInfoIcon = new PeerInfoIconTrading(tradingPeerNodeAddress,
role,
numPastTrades,
privateNotificationManager,
@ -536,6 +540,8 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
preferences,
model.dataModel.accountAgeWitnessService,
useDevPrivilegeKeys);
String key = tradeModel.getId();
avatarMap.put(key, peerInfoIcon);
setPadding(new Insets(1, 15, 0, 0));
setGraphic(peerInfoIcon);
} else {

View File

@ -22,6 +22,7 @@ import bisq.desktop.common.view.ActivatableViewAndModel;
import bisq.desktop.common.view.FxmlView;
import bisq.desktop.components.AutoTooltipLabel;
import bisq.desktop.components.HyperlinkWithIcon;
import bisq.desktop.components.PeerInfoIconMap;
import bisq.desktop.components.PeerInfoIconTrading;
import bisq.desktop.components.list.FilterBox;
import bisq.desktop.main.MainView;
@ -68,7 +69,6 @@ import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.Window;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ContextMenu;
@ -152,6 +152,8 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
private ChangeListener<Trade.DisputeState> disputeStateListener;
private ChangeListener<MediationResultState> mediationResultStateListener;
private ChangeListener<Number> getMempoolStatusListener;
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
private final PeerInfoIconMap avatarMap = new PeerInfoIconMap();
///////////////////////////////////////////////////////////////////////////////////////////
@ -357,6 +359,8 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
if (scene != null)
scene.removeEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler);
avatarMap.clear();
}
private void removeSelectedSubView() {
@ -829,7 +833,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
final NodeAddress tradingPeerNodeAddress = trade.getTradingPeerNodeAddress();
int numPastTrades = model.getNumPastTrades(trade);
String role = Res.get("peerInfoIcon.tooltip.tradePeer");
Node peerInfoIcon = new PeerInfoIconTrading(tradingPeerNodeAddress,
PeerInfoIconTrading peerInfoIcon = new PeerInfoIconTrading(tradingPeerNodeAddress,
role,
numPastTrades,
privateNotificationManager,
@ -837,6 +841,8 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
preferences,
model.accountAgeWitnessService,
useDevPrivilegeKeys);
String key = trade.getId();
avatarMap.put(key, peerInfoIcon);
setPadding(new Insets(1, 0, 0, 0));
setGraphic(peerInfoIcon);
} else {

View File

@ -23,8 +23,8 @@ import bisq.desktop.components.AutoTooltipLabel;
import bisq.desktop.components.AutoTooltipTableColumn;
import bisq.desktop.components.HyperlinkWithIcon;
import bisq.desktop.components.InputTextField;
import bisq.desktop.components.PeerInfoIcon;
import bisq.desktop.components.PeerInfoIconDispute;
import bisq.desktop.components.PeerInfoIconMap;
import bisq.desktop.main.overlays.popups.Popup;
import bisq.desktop.main.overlays.windows.ContractWindow;
import bisq.desktop.main.overlays.windows.DisputeSummaryWindow;
@ -126,7 +126,7 @@ import javax.annotation.Nullable;
import static bisq.desktop.util.FormBuilder.getIconForLabel;
import static bisq.desktop.util.FormBuilder.getRegularIconButton;
public abstract class DisputeView extends ActivatableView<VBox, Void> implements PeerInfoIcon.notify, DisputeChatPopup.ChatCallback {
public abstract class DisputeView extends ActivatableView<VBox, Void> implements DisputeChatPopup.ChatCallback {
public enum FilterResult {
NO_MATCH("No Match"),
NO_FILTER("No filter text"),
@ -191,7 +191,8 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> implements
private Map<String, Button> chatButtonByDispute = new HashMap<>();
private Map<String, JFXBadge> chatBadgeByDispute = new HashMap<>();
private Map<String, JFXBadge> newBadgeByDispute = new HashMap<>();
private Map<String, PeerInfoIconDispute> avatarMap = new HashMap<>();
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
private final PeerInfoIconMap avatarMap = new PeerInfoIconMap();
protected DisputeChatPopup chatPopup;
@ -369,6 +370,7 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> implements
filterTextField.textProperty().removeListener(filterTextFieldListener);
sortedList.comparatorProperty().unbind();
selectedDisputeSubscription.unsubscribe();
avatarMap.clear();
}
@ -1220,7 +1222,7 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> implements
super.updateItem(item, empty);
if (item != null && !empty) {
setText(getBuyerOnionAddressColumnLabel(item));
PeerInfoIconDispute peerInfoIconDispute = findOrCreateAvatar(tableRowProperty().get().getIndex(), item.getContract(), true);
PeerInfoIconDispute peerInfoIconDispute = createAvatar(tableRowProperty().get().getIndex(), item.getContract(), true);
setGraphic(peerInfoIconDispute);
} else {
setText("");
@ -1250,7 +1252,7 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> implements
super.updateItem(item, empty);
if (item != null && !empty) {
setText(getSellerOnionAddressColumnLabel(item));
PeerInfoIconDispute peerInfoIconDispute = findOrCreateAvatar(tableRowProperty().get().getIndex(), item.getContract(), false);
PeerInfoIconDispute peerInfoIconDispute = createAvatar(tableRowProperty().get().getIndex(), item.getContract(), false);
setGraphic(peerInfoIconDispute);
} else {
setText("");
@ -1477,7 +1479,7 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> implements
}
}
private PeerInfoIconDispute findOrCreateAvatar(Integer tableRowId, Contract contract, boolean isBuyer) {
private PeerInfoIconDispute createAvatar(Integer tableRowId, Contract contract, boolean isBuyer) {
NodeAddress nodeAddress = isBuyer ? contract.getBuyerNodeAddress() : contract.getSellerNodeAddress();
String key = tableRowId + nodeAddress.getHostNameWithoutPostFix() + (isBuyer ? "BUYER" : "SELLER");
Long accountAge = isBuyer ?
@ -1488,21 +1490,10 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> implements
disputeManager.getNrOfDisputes(isBuyer, contract),
accountAge,
preferences);
peerInfoIcon.setCallback(this);
avatarMap.put(key, peerInfoIcon);
return peerInfoIcon;
}
@Override
public void avatarTagUpdated() {
// callback from one avatar letting us know that the user updated the tag text.
// we update all avatars, as some could be sharing the same tag
log.info("Updating avatar tags, the avatarMap size is {}", avatarMap.size());
avatarMap.forEach((key, avatarIcon) -> {
avatarIcon.refreshTag();
});
}
@Override
public void onCloseDisputeFromChatWindow(Dispute dispute) {
handleOnProcessDispute(dispute);