diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/ServiceProvider.java b/apps/desktop/desktop/src/main/java/bisq/desktop/ServiceProvider.java
index 9f1bed8d78..47c7c24371 100644
--- a/apps/desktop/desktop/src/main/java/bisq/desktop/ServiceProvider.java
+++ b/apps/desktop/desktop/src/main/java/bisq/desktop/ServiceProvider.java
@@ -3,20 +3,16 @@
*
* 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
+ * 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
+ * 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 .
+ * along with Bisq. If not, see .
*/
package bisq.desktop;
diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/user/profile_card/ProfileCardController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/user/profile_card/ProfileCardController.java
index aa652341e7..2ec368b219 100644
--- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/user/profile_card/ProfileCardController.java
+++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/user/profile_card/ProfileCardController.java
@@ -30,6 +30,7 @@
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.overview.ProfileCardOverviewController;
+import bisq.desktop.main.content.user.profile_card.reputation.ProfileCardReputationController;
import bisq.desktop.overlay.OverlayController;
import bisq.user.banned.BannedUserService;
import bisq.user.identity.UserIdentityService;
@@ -81,6 +82,7 @@ public InitData(UserProfile userProfile) {
protected final UserIdentityService userIdentityService;
private final ProfileCardOverviewController profileCardOverviewController;
private final ProfileCardDetailsController profileCardDetailsController;
+ private final ProfileCardReputationController profileCardReputationController;
private Optional> selectedChannel;
private Optional ignoreUserStateHandler, closeHandler;
private Subscription userProfilePin;
@@ -95,6 +97,7 @@ public ProfileCardController(ServiceProvider serviceProvider) {
userIdentityService = serviceProvider.getUserService().getUserIdentityService();
profileCardOverviewController = new ProfileCardOverviewController(serviceProvider);
profileCardDetailsController = new ProfileCardDetailsController(serviceProvider);
+ profileCardReputationController = new ProfileCardReputationController(serviceProvider);
view = new ProfileCardView(model, this);
}
@@ -102,8 +105,9 @@ public ProfileCardController(ServiceProvider serviceProvider) {
public void onActivate() {
userProfilePin = EasyBind.subscribe(model.getUserProfile(), userProfile -> {
model.getReputationScore().set(reputationService.getReputationScore(userProfile));
- profileCardDetailsController.updateUserProfileData(userProfile);
profileCardOverviewController.updateUserProfileData(userProfile);
+ profileCardDetailsController.updateUserProfileData(userProfile);
+ profileCardReputationController.updateUserProfileData(userProfile);
boolean isMyProfile = userIdentityService.isUserIdentityPresent(userProfile.getId());
model.getShouldShowReportButton().set(!isMyProfile && selectedChannel.isPresent());
model.getShouldShowUserActionsMenu().set(!isMyProfile);
@@ -120,8 +124,8 @@ 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 USER_DETAILS_OFFERS -> Optional.of();
-// case USER_DETAILS_REPUTATION -> Optional.of();
+// case PROFILE_CARD_OFFERS -> Optional.of();
+ case PROFILE_CARD_REPUTATION -> Optional.of(profileCardReputationController);
default -> Optional.empty();
};
}
diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/user/profile_card/ProfileCardView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/user/profile_card/ProfileCardView.java
index 657307f528..6737abeceb 100644
--- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/user/profile_card/ProfileCardView.java
+++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/user/profile_card/ProfileCardView.java
@@ -58,8 +58,8 @@ 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.USER_CARD_OFFERS);
-// addTab(Res.get("user.profileCard.tab.reputation"), NavigationTarget.USER_CARD_REPUTATION);
+// addTab(Res.get("user.profileCard.tab.offers"), NavigationTarget.PROFILE_CARD_OFFERS);
+ addTab(Res.get("user.profileCard.tab.reputation"), NavigationTarget.PROFILE_CARD_REPUTATION);
}
@Override
diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/user/profile_card/reputation/ProfileCardReputationController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/user/profile_card/reputation/ProfileCardReputationController.java
new file mode 100644
index 0000000000..6e3b6c6157
--- /dev/null
+++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/user/profile_card/reputation/ProfileCardReputationController.java
@@ -0,0 +1,100 @@
+/*
+ * 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 .
+ */
+
+package bisq.desktop.main.content.user.profile_card.reputation;
+
+import bisq.desktop.ServiceProvider;
+import bisq.desktop.common.view.Controller;
+import bisq.user.profile.UserProfile;
+import bisq.user.reputation.AccountAgeService;
+import bisq.user.reputation.BondedReputationService;
+import bisq.user.reputation.ProfileAgeService;
+import bisq.user.reputation.ProofOfBurnService;
+import bisq.user.reputation.ReputationService;
+import bisq.user.reputation.ReputationSource;
+import bisq.user.reputation.SignedWitnessService;
+import lombok.Getter;
+
+import java.util.Optional;
+
+public class ProfileCardReputationController implements Controller {
+ @Getter
+ private final ProfileCardReputationView view;
+ private final ProfileCardReputationModel model;
+ private final ReputationService reputationService;
+
+ public ProfileCardReputationController(ServiceProvider serviceProvider) {
+ model = new ProfileCardReputationModel();
+ view = new ProfileCardReputationView(model, this);
+ reputationService = serviceProvider.getUserService().getReputationService();
+ }
+
+ @Override
+ public void onActivate() {
+ }
+
+ @Override
+ public void onDeactivate() {
+ }
+
+ public void updateUserProfileData(UserProfile userProfile) {
+ model.getListItems().clear();
+
+ ProofOfBurnService proofOfBurnService = reputationService.getProofOfBurnService();
+ Optional.ofNullable(proofOfBurnService.getDataSetByHash().get(userProfile.getProofOfBurnKey()))
+ .ifPresent(dataSet -> model.getListItems().addAll(dataSet.stream()
+ .map(data -> new ProfileCardReputationView.ListItem(ReputationSource.BURNED_BSQ,
+ data.getBlockTime(),
+ proofOfBurnService.calculateScore(data),
+ data.getAmount()))
+ .toList()));
+
+ BondedReputationService bondedReputationService = reputationService.getBondedReputationService();
+ Optional.ofNullable(bondedReputationService.getDataSetByHash().get(userProfile.getBondedReputationKey()))
+ .ifPresent(dataSet -> model.getListItems().addAll(dataSet.stream()
+ .map(data -> new ProfileCardReputationView.ListItem(ReputationSource.BSQ_BOND,
+ data.getBlockTime(),
+ bondedReputationService.calculateScore(data),
+ Optional.of(data.getAmount()),
+ Optional.of(data.getLockTime())))
+ .toList()));
+
+ AccountAgeService accountAgeService = reputationService.getAccountAgeService();
+ Optional.ofNullable(accountAgeService.getDataSetByHash().get(userProfile.getAccountAgeKey()))
+ .ifPresent(dataSet -> model.getListItems().addAll(dataSet.stream()
+ .map(data -> new ProfileCardReputationView.ListItem(ReputationSource.BISQ1_ACCOUNT_AGE,
+ data.getDate(),
+ accountAgeService.calculateScore(data)))
+ .toList()));
+
+ SignedWitnessService signedWitnessService = reputationService.getSignedWitnessService();
+ Optional.ofNullable(signedWitnessService.getDataSetByHash().get(userProfile.getSignedWitnessKey()))
+ .ifPresent(dataSet -> model.getListItems().addAll(dataSet.stream()
+ .map(data -> new ProfileCardReputationView.ListItem(ReputationSource.BISQ1_SIGNED_ACCOUNT_AGE_WITNESS,
+ data.getWitnessSignDate(),
+ signedWitnessService.calculateScore(data)))
+ .toList()));
+
+ ProfileAgeService profileAgeService = reputationService.getProfileAgeService();
+ Optional.ofNullable(profileAgeService.getDataSetByHash().get(userProfile.getProfileAgeKey()))
+ .ifPresent(dataSet -> model.getListItems().addAll(dataSet.stream()
+ .map(data -> new ProfileCardReputationView.ListItem(ReputationSource.PROFILE_AGE,
+ data.getDate(),
+ profileAgeService.calculateScore(data)))
+ .toList()));
+ }
+}
diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/user/profile_card/reputation/ProfileCardReputationModel.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/user/profile_card/reputation/ProfileCardReputationModel.java
new file mode 100644
index 0000000000..84518fb5f9
--- /dev/null
+++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/user/profile_card/reputation/ProfileCardReputationModel.java
@@ -0,0 +1,30 @@
+/*
+ * 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 .
+ */
+
+package bisq.desktop.main.content.user.profile_card.reputation;
+
+import bisq.desktop.common.view.Model;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Getter
+public class ProfileCardReputationModel implements Model {
+ private final ObservableList listItems = FXCollections.observableArrayList();
+}
diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/user/profile_card/reputation/ProfileCardReputationView.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/user/profile_card/reputation/ProfileCardReputationView.java
new file mode 100644
index 0000000000..7394228ef3
--- /dev/null
+++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/user/profile_card/reputation/ProfileCardReputationView.java
@@ -0,0 +1,144 @@
+/*
+ * 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 .
+ */
+
+package bisq.desktop.main.content.user.profile_card.reputation;
+
+import bisq.common.monetary.Coin;
+import bisq.desktop.common.view.View;
+import bisq.desktop.components.table.BisqTableColumn;
+import bisq.desktop.components.table.BisqTableView;
+import bisq.desktop.components.table.DateColumnUtil;
+import bisq.desktop.components.table.DateTableItem;
+import bisq.i18n.Res;
+import bisq.presentation.formatters.AmountFormatter;
+import bisq.presentation.formatters.DateFormatter;
+import bisq.presentation.formatters.TimeFormatter;
+import bisq.user.reputation.ReputationSource;
+import javafx.geometry.Insets;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.VBox;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Comparator;
+import java.util.Optional;
+
+@Slf4j
+public class ProfileCardReputationView extends View {
+ private final BisqTableView tableView;
+
+ public ProfileCardReputationView(ProfileCardReputationModel model,
+ ProfileCardReputationController controller) {
+ super(new VBox(), model, controller);
+
+ VBox vBox = new VBox();
+ vBox.setFillWidth(true);
+ vBox.getStyleClass().add("header");
+ tableView = new BisqTableView<>(model.getListItems());
+ tableView.getStyleClass().addAll("reputation-table", "rich-table-view");
+ tableView.allowVerticalScrollbar();
+ configTableView();
+ root.getChildren().addAll(vBox, tableView);
+ root.setPadding(new Insets(20, 0, 0, 0));
+ root.getStyleClass().add("reputation");
+ }
+
+ @Override
+ protected void onViewAttached() {
+ tableView.initialize();
+ }
+
+ @Override
+ protected void onViewDetached() {
+ tableView.dispose();
+ }
+
+ private void configTableView() {
+ BisqTableColumn dateColumn = DateColumnUtil.getDateColumn(tableView.getSortOrder());
+ dateColumn.setMinWidth(100);
+ tableView.getColumns().add(dateColumn);
+
+ tableView.getColumns().add(new BisqTableColumn.Builder()
+ .title(Res.get("reputation.details.table.columns.source"))
+ .left()
+ .comparator(Comparator.comparing(ListItem::getReputationSource))
+ .valueSupplier(ListItem::getSourceString)
+ .build());
+ tableView.getColumns().add(new BisqTableColumn.Builder()
+ .title(Res.get("reputation.details.table.columns.score"))
+ .comparator(Comparator.comparing(ListItem::getScore))
+ .valueSupplier(ListItem::getScoreString)
+ .build());
+ tableView.getColumns().add(new BisqTableColumn.Builder()
+ .title(Res.get("temporal.age"))
+ .comparator(Comparator.comparing(ListItem::getAge))
+ .valueSupplier(ListItem::getAgeString)
+ .build());
+ tableView.getColumns().add(new BisqTableColumn.Builder()
+ .title(Res.get("offer.amount"))
+ .comparator(Comparator.comparing(ListItem::getAmount))
+ .valueSupplier(ListItem::getAmountString)
+ .build());
+ tableView.getColumns().add(new BisqTableColumn.Builder()
+ .title(Res.get("reputation.details.table.columns.lockTime"))
+ .comparator(Comparator.comparing(ListItem::getLockTime))
+ .valueSupplier(ListItem::getLockTimeString)
+ .build());
+ }
+
+ @EqualsAndHashCode(onlyExplicitlyIncluded = true)
+ @Getter
+ static class ListItem implements DateTableItem {
+ @EqualsAndHashCode.Include
+ private final ReputationSource reputationSource;
+ @EqualsAndHashCode.Include
+ private final long date, score, amount, lockTime;
+
+ private final long age;
+ private final String dateString, timeString, sourceString, ageString, amountString, scoreString, lockTimeString;
+
+ public ListItem(ReputationSource reputationSource, long blockTime, long score) {
+ this(reputationSource, blockTime, score, Optional.empty(), Optional.empty());
+ }
+
+ public ListItem(ReputationSource reputationSource, long blockTime, long score, long amount) {
+ this(reputationSource, blockTime, score, Optional.of(amount), Optional.empty());
+ }
+
+ public ListItem(ReputationSource reputationSource,
+ long blockTime,
+ long score,
+ Optional optionalAmount,
+ Optional optionalLockTime) {
+ this.reputationSource = reputationSource;
+ this.date = blockTime;
+ this.score = score;
+ this.amount = optionalAmount.orElse(0L);
+ this.lockTime = optionalLockTime.orElse(0L);
+
+ dateString = DateFormatter.formatDate(blockTime);
+ timeString = DateFormatter.formatTime(blockTime);
+ age = TimeFormatter.getAgeInDays(blockTime);
+ ageString = TimeFormatter.formatAgeInDays(blockTime);
+ sourceString = reputationSource.getDisplayString();
+ amountString = optionalAmount.map(amount -> AmountFormatter.formatAmountWithCode(Coin.fromValue(amount, "BSQ"))).orElse("-");
+ scoreString = String.valueOf(score);
+ lockTimeString = optionalLockTime.map(String::valueOf).orElse("-");
+ }
+ }
+}
diff --git a/apps/desktop/desktop/src/main/resources/css/user.css b/apps/desktop/desktop/src/main/resources/css/user.css
index 86795018c4..ccb2d34057 100644
--- a/apps/desktop/desktop/src/main/resources/css/user.css
+++ b/apps/desktop/desktop/src/main/resources/css/user.css
@@ -143,3 +143,30 @@
.profile-card .bisq-common-bg {
-fx-padding: 35 !important;
}
+
+.profile-card .reputation .header {
+ -fx-pref-height: 8;
+ -fx-background-color: -bisq-dark-grey-30;
+ -fx-background-radius: 8 8 0 0;
+}
+
+.profile-card .reputation .reputation-table.table-view {
+ -fx-pref-height: 300;
+ -fx-background-radius: 0 0 8 8;
+ -fx-background-insets: 0;
+ -fx-padding: 0;
+ -fx-border-width: 0;
+}
+
+.profile-card .reputation .reputation-table.table-view .table-cell .text {
+ -fx-font-size: 0.9em;
+ -fx-padding: 0;
+}
+
+.profile-card .reputation .reputation-table.table-view .column-header {
+ -fx-pref-height: 25;
+}
+
+.profile-card .reputation .reputation-table.table-view .table-row-cell {
+ -fx-border-width: 0;
+}