Skip to content

Commit

Permalink
Merge pull request #3037 from axpoems/add-profileCard-offers-page
Browse files Browse the repository at this point in the history
Add user offers to profile card
  • Loading branch information
HenrikJannsen authored Dec 3, 2024
2 parents 7e7a5a3 + f0a0d71 commit 3bf4446
Show file tree
Hide file tree
Showing 18 changed files with 407 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,25 @@

package bisq.desktop.main.content.bisq_easy;

import bisq.account.payment_method.BitcoinPaymentMethod;
import bisq.account.payment_method.FiatPaymentMethod;
import bisq.account.payment_method.PaymentMethod;
import bisq.common.data.Quadruple;
import bisq.desktop.common.Layout;
import bisq.desktop.common.utils.ImageUtil;
import bisq.desktop.components.controls.BisqTooltip;
import bisq.desktop.components.table.BisqTableView;
import bisq.security.DigestUtil;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;

import java.math.BigInteger;
import java.util.List;

public class BisqEasyViewUtils {
private static final String[] customPaymentIconIds = {
Expand Down Expand Up @@ -70,4 +77,37 @@ public static StackPane getCustomPaymentMethodIcon(String customPaymentMethod) {
stackPane.setAlignment(Pos.CENTER);
return stackPane;
}

public static HBox getPaymentAndSettlementMethodsBox(List<FiatPaymentMethod> paymentMethods,
List<BitcoinPaymentMethod> settlementMethods) {
HBox hBox = new HBox(8);
for (FiatPaymentMethod paymentMethod : paymentMethods) {
hBox.getChildren().add(createMethodLabel(paymentMethod));
}

ImageView icon = ImageUtil.getImageViewById("interchangeable-grey");
Label interchangeableIcon = new Label();
interchangeableIcon.setGraphic(icon);
interchangeableIcon.setPadding(new Insets(0, 0, 1, 0));
hBox.getChildren().add(interchangeableIcon);

for (BitcoinPaymentMethod settlementMethod : settlementMethods) {
Label label = createMethodLabel(settlementMethod);
ColorAdjust colorAdjust = new ColorAdjust();
colorAdjust.setBrightness(-0.2);
label.setEffect(colorAdjust);
hBox.getChildren().add(label);
}
return hBox;
}

private static Label createMethodLabel(PaymentMethod<?> paymentMethod) {
Node icon = !paymentMethod.isCustomPaymentMethod()
? ImageUtil.getImageViewById(paymentMethod.getName())
: BisqEasyViewUtils.getCustomPaymentMethodIcon(paymentMethod.getDisplayString());
Label label = new Label();
label.setGraphic(icon);
label.setTooltip(new BisqTooltip(paymentMethod.getDisplayString()));
return label;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
import bisq.offer.price.OfferPriceFormatter;
import bisq.offer.price.PriceUtil;
import bisq.offer.price.spec.FixPriceSpec;
import bisq.offer.price.spec.FloatPriceSpec;
import bisq.offer.price.spec.PriceSpecFormatter;
import bisq.presentation.formatters.PercentageFormatter;
import bisq.user.profile.UserProfile;
import bisq.user.reputation.ReputationScore;
Expand All @@ -60,21 +60,21 @@ public class OfferbookListItem {
private final ReputationService reputationService;
private final UserProfile senderUserProfile;
private final String userNickname, formattedRangeQuoteAmount, bitcoinPaymentMethodsAsString,
fiatPaymentMethodsAsString, authorUserProfileId;
fiatPaymentMethodsAsString, authorUserProfileId, marketCurrencyCode, offerType;
private final ReputationScore reputationScore;
private final List<FiatPaymentMethod> fiatPaymentMethods;
private final List<BitcoinPaymentMethod> bitcoinPaymentMethods;
private final boolean isFixPrice;
private final Monetary quoteSideMinAmount;
private final long totalScore;
private double priceSpecAsPercent;
private String formattedPercentagePrice, priceTooltipText;
private final Pin marketPriceByCurrencyMapPin;
private String formattedPercentagePrice, priceTooltipText;

OfferbookListItem(BisqEasyOfferbookMessage bisqEasyOfferbookMessage,
UserProfile senderUserProfile,
ReputationService reputationService,
MarketPriceService marketPriceService) {
public OfferbookListItem(BisqEasyOfferbookMessage bisqEasyOfferbookMessage,
UserProfile senderUserProfile,
ReputationService reputationService,
MarketPriceService marketPriceService) {
this.bisqEasyOfferbookMessage = bisqEasyOfferbookMessage;

bisqEasyOffer = bisqEasyOfferbookMessage.getBisqEasyOffer().orElseThrow();
Expand All @@ -94,6 +94,10 @@ public class OfferbookListItem {
formattedRangeQuoteAmount = OfferAmountFormatter.formatQuoteAmount(marketPriceService, bisqEasyOffer, false);
isFixPrice = bisqEasyOffer.getPriceSpec() instanceof FixPriceSpec;
authorUserProfileId = bisqEasyOfferbookMessage.getAuthorUserProfileId();
marketCurrencyCode = bisqEasyOffer.getMarket().getQuoteCurrencyCode();
offerType = bisqEasyOffer.getDirection().isBuy()
? Res.get("bisqEasy.offerbook.offerList.table.columns.offerType.buy")
: Res.get("bisqEasy.offerbook.offerList.table.columns.offerType.sell");

reputationScore = reputationService.getReputationScore(senderUserProfile);
totalScore = reputationScore.getTotalScore();
Expand All @@ -113,15 +117,9 @@ boolean isBuyOffer() {

private void updatePriceSpecAsPercent() {
priceSpecAsPercent = PriceUtil.findPercentFromMarketPrice(marketPriceService, bisqEasyOffer).orElseThrow();
formattedPercentagePrice = PercentageFormatter.formatToPercentWithSymbol(priceSpecAsPercent);
String price = OfferPriceFormatter.formatQuote(marketPriceService, bisqEasyOffer);
if (bisqEasyOffer.getPriceSpec() instanceof FixPriceSpec) {
priceTooltipText = Res.get("bisqEasy.offerbook.offerList.table.columns.price.tooltip.fixPrice", price, formattedPercentagePrice);
} else if (bisqEasyOffer.getPriceSpec() instanceof FloatPriceSpec) {
priceTooltipText = Res.get("bisqEasy.offerbook.offerList.table.columns.price.tooltip.floatPrice", formattedPercentagePrice, price);
} else {
priceTooltipText = Res.get("bisqEasy.offerbook.offerList.table.columns.price.tooltip.marketPrice", price);
}
formattedPercentagePrice = PercentageFormatter.formatToPercentWithSignAndSymbol(priceSpecAsPercent);
String offerPrice = OfferPriceFormatter.formatQuote(marketPriceService, bisqEasyOffer);
priceTooltipText = PriceSpecFormatter.getFormattedPriceSpecWithOfferPrice(bisqEasyOffer.getPriceSpec(), offerPrice);
}

private List<FiatPaymentMethod> retrieveAndSortFiatPaymentMethods() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ private MessageBox createMessage(ChatMessageListItem<? extends ChatMessage, ? ex
ListView<ChatMessageListItem<? extends ChatMessage, ? extends ChatChannel<? extends ChatMessage>>> list) {
if (item.isLeaveChatMessage()) {
if (item.getChatMessage() instanceof BisqEasyOpenTradeMessage) {
return new TradePeerLefMessageBox(item, controller);
return new TradePeerLeftMessageBox(item, controller);
} else {
return new PeerLeftMessageBox(item, controller);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@

package bisq.desktop.main.content.chat.message_container.list.message_box;

import bisq.account.payment_method.BitcoinPaymentMethod;
import bisq.account.payment_method.FiatPaymentMethod;
import bisq.account.payment_method.PaymentMethod;
import bisq.chat.ChatChannel;
import bisq.chat.ChatMessage;
import bisq.chat.Citation;
Expand Down Expand Up @@ -47,13 +44,10 @@
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.effect.BlurType;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
Expand Down Expand Up @@ -273,38 +267,12 @@ private HBox createAndGetAmountAndPriceBox() {
}

private HBox createAndGetPaymentAndSettlementMethodsBox() {
HBox hBox = new HBox(8);
if (item.isBisqEasyPublicChatMessageWithOffer()) {
for (FiatPaymentMethod fiatPaymentMethod : item.getBisqEasyOfferPaymentMethods()) {
hBox.getChildren().add(createMethodLabel(fiatPaymentMethod));
}

ImageView icon = ImageUtil.getImageViewById("interchangeable-grey");
Label interchangeableIcon = new Label();
interchangeableIcon.setGraphic(icon);
interchangeableIcon.setPadding(new Insets(0, 0, 1, 0));
hBox.getChildren().add(interchangeableIcon);

for (BitcoinPaymentMethod bitcoinPaymentMethod : item.getBisqEasyOfferSettlementMethods()) {
Label label = createMethodLabel(bitcoinPaymentMethod);
ColorAdjust colorAdjust = new ColorAdjust();
colorAdjust.setBrightness(-0.2);
label.setEffect(colorAdjust);
hBox.getChildren().add(label);
}
HBox hBox = BisqEasyViewUtils.getPaymentAndSettlementMethodsBox(item.getBisqEasyOfferPaymentMethods(), item.getBisqEasyOfferSettlementMethods());
hBox.setAlignment(Pos.BOTTOM_LEFT);
return hBox;
}
hBox.setAlignment(Pos.BOTTOM_LEFT);
return hBox;
}

private Label createMethodLabel(PaymentMethod<?> paymentMethod) {
Node icon = !paymentMethod.isCustomPaymentMethod()
? ImageUtil.getImageViewById(paymentMethod.getName())
: BisqEasyViewUtils.getCustomPaymentMethodIcon(paymentMethod.getDisplayString());
Label label = new Label();
label.setGraphic(icon);
label.setTooltip(new BisqTooltip(paymentMethod.getDisplayString()));
return label;
return new HBox();
}

private VBox createAndGetQuotedMessageBox() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;

public final class TradePeerLefMessageBox extends PeerProtocolLogMessageBox {
public TradePeerLefMessageBox(ChatMessageListItem<? extends ChatMessage, ? extends ChatChannel<? extends ChatMessage>> item,
ChatMessagesListController controller) {
public final class TradePeerLeftMessageBox extends PeerProtocolLogMessageBox {
public TradePeerLeftMessageBox(ChatMessageListItem<? extends ChatMessage, ? extends ChatChannel<? extends ChatMessage>> item,
ChatMessagesListController controller) {
super(item);

BisqEasyOpenTradeMessage bisqEasyOpenTradeMessage = (BisqEasyOpenTradeMessage) item.getChatMessage();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import bisq.desktop.common.view.TabController;
import bisq.desktop.main.content.components.ReportToModeratorWindow;
import bisq.desktop.main.content.user.profile_card.details.ProfileCardDetailsController;
import bisq.desktop.main.content.user.profile_card.offers.ProfileCardOffersController;
import bisq.desktop.main.content.user.profile_card.overview.ProfileCardOverviewController;
import bisq.desktop.main.content.user.profile_card.reputation.ProfileCardReputationController;
import bisq.desktop.overlay.OverlayController;
Expand Down Expand Up @@ -83,6 +84,7 @@ public InitData(UserProfile userProfile) {
private final ProfileCardOverviewController profileCardOverviewController;
private final ProfileCardDetailsController profileCardDetailsController;
private final ProfileCardReputationController profileCardReputationController;
private final ProfileCardOffersController profileCardOffersController;
private Optional<ChatChannel<? extends ChatMessage>> selectedChannel;
private Optional<Runnable> ignoreUserStateHandler, closeHandler;
private Subscription userProfilePin;
Expand All @@ -98,6 +100,7 @@ public ProfileCardController(ServiceProvider serviceProvider) {
profileCardOverviewController = new ProfileCardOverviewController(serviceProvider);
profileCardDetailsController = new ProfileCardDetailsController(serviceProvider);
profileCardReputationController = new ProfileCardReputationController(serviceProvider);
profileCardOffersController = new ProfileCardOffersController(serviceProvider);
view = new ProfileCardView(model, this);
}

Expand All @@ -108,6 +111,7 @@ public void onActivate() {
profileCardOverviewController.updateUserProfileData(userProfile);
profileCardDetailsController.updateUserProfileData(userProfile);
profileCardReputationController.updateUserProfileData(userProfile);
profileCardOffersController.updateUserProfileData(userProfile);
boolean isMyProfile = userIdentityService.isUserIdentityPresent(userProfile.getId());
model.getShouldShowReportButton().set(!isMyProfile && selectedChannel.isPresent());
model.getShouldShowUserActionsMenu().set(!isMyProfile);
Expand All @@ -124,7 +128,7 @@ protected Optional<? extends Controller> createController(NavigationTarget navig
return switch (navigationTarget) {
case PROFILE_CARD_OVERVIEW -> Optional.of(profileCardOverviewController);
case PROFILE_CARD_DETAILS -> Optional.of(profileCardDetailsController);
// case PROFILE_CARD_OFFERS -> Optional.of();
case PROFILE_CARD_OFFERS -> Optional.of(profileCardOffersController);
case PROFILE_CARD_REPUTATION -> Optional.of(profileCardReputationController);
default -> Optional.empty();
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public ProfileCardView(ProfileCardModel model, ProfileCardController controller)

addTab(Res.get("user.profileCard.tab.overview"), NavigationTarget.PROFILE_CARD_OVERVIEW);
addTab(Res.get("user.profileCard.tab.details"), NavigationTarget.PROFILE_CARD_DETAILS);
// addTab(Res.get("user.profileCard.tab.offers"), NavigationTarget.PROFILE_CARD_OFFERS);
addTab(Res.get("user.profileCard.tab.offers"), NavigationTarget.PROFILE_CARD_OFFERS);
addTab(Res.get("user.profileCard.tab.reputation"), NavigationTarget.PROFILE_CARD_REPUTATION);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* 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.main.content.user.profile_card.offers;

import bisq.bonded_roles.market_price.MarketPriceService;
import bisq.chat.bisqeasy.offerbook.BisqEasyOfferbookChannel;
import bisq.chat.bisqeasy.offerbook.BisqEasyOfferbookChannelService;
import bisq.desktop.ServiceProvider;
import bisq.desktop.common.view.Controller;
import bisq.desktop.main.content.bisq_easy.offerbook.offerbook_list.OfferbookListItem;
import bisq.user.profile.UserProfile;
import bisq.user.reputation.ReputationService;
import lombok.Getter;

import java.util.ArrayList;
import java.util.List;

public class ProfileCardOffersController implements Controller {
@Getter
private final ProfileCardOffersView view;
private final ProfileCardOffersModel model;
private final BisqEasyOfferbookChannelService bisqEasyOfferbookChannelService;
private final ReputationService reputationService;
private final MarketPriceService marketPriceService;

public ProfileCardOffersController(ServiceProvider serviceProvider) {
model = new ProfileCardOffersModel();
view = new ProfileCardOffersView(model, this);
bisqEasyOfferbookChannelService = serviceProvider.getChatService().getBisqEasyOfferbookChannelService();
reputationService = serviceProvider.getUserService().getReputationService();
marketPriceService = serviceProvider.getBondedRolesService().getMarketPriceService();
}

@Override
public void onActivate() {
}

@Override
public void onDeactivate() {
}

public void updateUserProfileData(UserProfile userProfile) {
model.getListItems().clear();

List<OfferbookListItem> userOffers = new ArrayList<>();
for (BisqEasyOfferbookChannel market : bisqEasyOfferbookChannelService.getChannels()) {
userOffers.addAll(market.getChatMessages().stream()
.filter(chatMessage -> chatMessage.hasBisqEasyOffer()
&& chatMessage.getAuthorUserProfileId().equals(userProfile.getId()))
.map(userChatMessageWithOffer -> new OfferbookListItem(
userChatMessageWithOffer, userProfile, reputationService, marketPriceService))
.toList());
}
model.getListItems().addAll(userOffers);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* 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.main.content.user.profile_card.offers;

import bisq.desktop.common.view.Model;
import bisq.desktop.main.content.bisq_easy.offerbook.offerbook_list.OfferbookListItem;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Getter
public class ProfileCardOffersModel implements Model {
private final ObservableList<OfferbookListItem> listItems = FXCollections.observableArrayList();
}
Loading

0 comments on commit 3bf4446

Please sign in to comment.