diff --git a/build.gradle b/build.gradle index 82086309..c01d3672 100644 --- a/build.gradle +++ b/build.gradle @@ -70,6 +70,7 @@ dependencies { exclude group: 'org.openjfx', module: 'javafx-media' } implementation('dev.bwt:bwt-jni:0.1.7') + implementation('net.sourceforge.javacsv:javacsv:2.0') testImplementation('junit:junit:4.12') } diff --git a/src/main/java/com/sparrowwallet/sparrow/control/EntryCell.java b/src/main/java/com/sparrowwallet/sparrow/control/EntryCell.java index 91f99711..30d41b9f 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/EntryCell.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/EntryCell.java @@ -25,8 +25,8 @@ import java.text.SimpleDateFormat; import java.util.*; import java.util.stream.Collectors; -class EntryCell extends TreeTableCell { - private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm"); +public class EntryCell extends TreeTableCell { + public static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm"); public EntryCell() { super(); diff --git a/src/main/java/com/sparrowwallet/sparrow/glyphfont/FontAwesome5.java b/src/main/java/com/sparrowwallet/sparrow/glyphfont/FontAwesome5.java index cf9fd058..3f0139a4 100644 --- a/src/main/java/com/sparrowwallet/sparrow/glyphfont/FontAwesome5.java +++ b/src/main/java/com/sparrowwallet/sparrow/glyphfont/FontAwesome5.java @@ -29,6 +29,7 @@ public class FontAwesome5 extends GlyphFont { EXTERNAL_LINK_ALT('\uf35d'), ELLIPSIS_H('\uf141'), EYE('\uf06e'), + FILE_CSV('\uf6dd'), HAND_HOLDING('\uf4bd'), HAND_HOLDING_MEDICAL('\ue05c'), HISTORY('\uf1da'), diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/TransactionsController.java b/src/main/java/com/sparrowwallet/sparrow/wallet/TransactionsController.java index ccdadb24..16f7f38b 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/TransactionsController.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/TransactionsController.java @@ -1,6 +1,9 @@ package com.sparrowwallet.sparrow.wallet; +import com.csvreader.CsvWriter; import com.google.common.eventbus.Subscribe; +import com.sparrowwallet.drongo.BitcoinUnit; +import com.sparrowwallet.drongo.protocol.Transaction; import com.sparrowwallet.sparrow.AppServices; import com.sparrowwallet.sparrow.CurrencyRate; import com.sparrowwallet.sparrow.EventManager; @@ -8,14 +11,26 @@ import com.sparrowwallet.sparrow.control.*; import com.sparrowwallet.sparrow.event.*; import com.sparrowwallet.sparrow.net.ExchangeSource; import javafx.collections.ListChangeListener; +import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.Initializable; +import javafx.scene.control.Button; import javafx.scene.control.TreeItem; - +import javafx.stage.FileChooser; +import javafx.stage.Stage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Locale; import java.util.ResourceBundle; public class TransactionsController extends WalletFormController implements Initializable { + private static final Logger log = LoggerFactory.getLogger(TransactionsController.class); @FXML private CoinLabel balance; @@ -38,6 +53,9 @@ public class TransactionsController extends WalletFormController implements Init @FXML private BalanceChart balanceChart; + @FXML + private Button exportCsv; + @Override public void initialize(URL location, ResourceBundle resources) { EventManager.get().register(this); @@ -81,6 +99,41 @@ public class TransactionsController extends WalletFormController implements Init transactionCount.setText(walletTransactionsEntry.getChildren() != null ? Integer.toString(walletTransactionsEntry.getChildren().size()) : "0"); } + public void exportCSV(ActionEvent event) { + WalletTransactionsEntry walletTransactionsEntry = getWalletForm().getWalletTransactionsEntry(); + + Stage window = new Stage(); + FileChooser fileChooser = new FileChooser(); + fileChooser.setTitle("Export Transactions as CSV"); + fileChooser.setInitialFileName(getWalletForm().getWallet().getName() + ".csv"); + + File file = fileChooser.showSaveDialog(window); + if(file != null) { + try(FileOutputStream outputStream = new FileOutputStream(file)) { + CsvWriter writer = new CsvWriter(outputStream, ',', StandardCharsets.UTF_8); + writer.writeRecord(new String[] {"Date", "Label", "Value", "Balance"}); + for(Entry entry : walletTransactionsEntry.getChildren()) { + TransactionEntry txEntry = (TransactionEntry)entry; + writer.write(EntryCell.DATE_FORMAT.format(txEntry.getBlockTransaction().getDate())); + writer.write(txEntry.getLabel()); + writer.write(getCoinValue(txEntry.getValue())); + writer.write(getCoinValue(txEntry.getBalance())); + writer.endRecord(); + } + writer.close(); + } catch(IOException e) { + log.error("Error exporting transactions as CSV", e); + AppServices.showErrorDialog("Error exporting transactions as CSV", e.getMessage()); + } + } + } + + private String getCoinValue(Long value) { + return BitcoinUnit.BTC.equals(transactionsTable.getBitcoinUnit()) ? + CoinLabel.getBTCFormat().format(value.doubleValue() / Transaction.SATOSHIS_PER_BITCOIN) : + String.format(Locale.ENGLISH, "%d", value); + } + @Subscribe public void walletNodesChanged(WalletNodesChangedEvent event) { if(event.getWallet().equals(walletForm.getWallet())) { diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 2d772351..eb4d6e91 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -27,4 +27,5 @@ open module com.sparrowwallet.sparrow { requires slf4j.api; requires bwt.jni; requires jtorctl; + requires javacsv; } \ No newline at end of file diff --git a/src/main/resources/com/sparrowwallet/sparrow/app.css b/src/main/resources/com/sparrowwallet/sparrow/app.css index 3142fcef..b36096b7 100644 --- a/src/main/resources/com/sparrowwallet/sparrow/app.css +++ b/src/main/resources/com/sparrowwallet/sparrow/app.css @@ -34,3 +34,8 @@ -fx-background-color: linear-gradient(to bottom, derive(-fx-text-box-border, -20%), derive(-fx-text-box-border, -30%)), linear-gradient(to bottom, derive(#50a14f, 30%), #50a14f); -fx-background-insets: 0, 1; } + +.public-server.toggle-switch:selected .thumb-area { + -fx-background-color: linear-gradient(to bottom, derive(-fx-text-box-border, -20%), derive(-fx-text-box-border, -30%)), linear-gradient(to bottom, derive(gold, 30%), gold); + -fx-background-insets: 0, 1; +} \ No newline at end of file diff --git a/src/main/resources/com/sparrowwallet/sparrow/wallet/transactions.css b/src/main/resources/com/sparrowwallet/sparrow/wallet/transactions.css index 5177578e..a324d0b4 100644 --- a/src/main/resources/com/sparrowwallet/sparrow/wallet/transactions.css +++ b/src/main/resources/com/sparrowwallet/sparrow/wallet/transactions.css @@ -22,4 +22,16 @@ .chart-line-symbol.selected { -fx-background-color: rgba(30, 136, 207, 0.6); +} + +#exportCsv { + -fx-border-style: none; + -fx-border-width: 0; + -fx-border-insets: 0; + -fx-background-color: transparent; + -fx-opacity: 0.7; +} + +#exportCsv:hover { + -fx-opacity: 1.0; } \ No newline at end of file diff --git a/src/main/resources/com/sparrowwallet/sparrow/wallet/transactions.fxml b/src/main/resources/com/sparrowwallet/sparrow/wallet/transactions.fxml index 9bbdc27a..26bf7f00 100644 --- a/src/main/resources/com/sparrowwallet/sparrow/wallet/transactions.fxml +++ b/src/main/resources/com/sparrowwallet/sparrow/wallet/transactions.fxml @@ -15,6 +15,7 @@ +
@@ -40,6 +41,11 @@ +