Merge remote-tracking branch 'origin/master'
6
.github/workflows/package.yaml
vendored
|
|
@ -30,6 +30,9 @@ jobs:
|
|||
- name: Package tar distribution
|
||||
if: ${{ runner.os == 'Linux' }}
|
||||
run: ./gradlew packageTarDistribution
|
||||
- name: Repackage deb distribution
|
||||
if: ${{ runner.os == 'Linux' }}
|
||||
run: ./repackage.sh
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
|
@ -43,6 +46,9 @@ jobs:
|
|||
- name: Package headless tar distribution
|
||||
if: ${{ runner.os == 'Linux' }}
|
||||
run: ./gradlew -Djava.awt.headless=true packageTarDistribution
|
||||
- name: Repackage headless deb distribution
|
||||
if: ${{ runner.os == 'Linux' }}
|
||||
run: ./repackage.sh
|
||||
- name: Upload Headless Artifact
|
||||
if: ${{ runner.os == 'Linux' }}
|
||||
uses: actions/upload-artifact@v4
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ plugins {
|
|||
id 'org-openjfx-javafxplugin'
|
||||
id 'org.beryx.jlink' version '3.1.1'
|
||||
id 'org.gradlex.extra-java-module-info' version '1.9'
|
||||
id 'io.matthewnelson.kmp.tor.resource-filterjar' version '408.16.2'
|
||||
id 'io.matthewnelson.kmp.tor.resource-filterjar' version '408.16.3'
|
||||
}
|
||||
|
||||
def os = org.gradle.internal.os.OperatingSystem.current()
|
||||
|
|
@ -20,7 +20,7 @@ if(System.getProperty("os.arch") == "aarch64") {
|
|||
def headless = "true".equals(System.getProperty("java.awt.headless"))
|
||||
|
||||
group 'com.sparrowwallet'
|
||||
version '2.1.4'
|
||||
version '2.2.2'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
|
@ -76,7 +76,7 @@ dependencies {
|
|||
implementation('co.nstant.in:cbor:0.9')
|
||||
implementation('org.openpnp:openpnp-capture-java:0.0.28-5')
|
||||
implementation("io.matthewnelson.kmp-tor:runtime:2.2.1")
|
||||
implementation("io.matthewnelson.kmp-tor:resource-exec-tor-gpl:408.16.2")
|
||||
implementation("io.matthewnelson.kmp-tor:resource-exec-tor-gpl:408.16.3")
|
||||
implementation('org.jetbrains.kotlinx:kotlinx-coroutines-javafx:1.10.1') {
|
||||
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-common'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ sudo apt install -y rpm fakeroot binutils
|
|||
First, assign a temporary variable in your shell for the specific release you want to build. For the current one specify:
|
||||
|
||||
```shell
|
||||
GIT_TAG="2.1.3"
|
||||
GIT_TAG="2.2.1"
|
||||
```
|
||||
|
||||
The project can then be initially cloned as follows:
|
||||
|
|
|
|||
48
repackage.sh
Executable file
|
|
@ -0,0 +1,48 @@
|
|||
#!/bin/bash
|
||||
set -e # Exit on any error
|
||||
|
||||
# Define paths
|
||||
BUILD_DIR="build"
|
||||
JPACKAGE_DIR="$BUILD_DIR/jpackage"
|
||||
TEMP_DIR="$BUILD_DIR/repackage"
|
||||
|
||||
# Find the .deb file in build/jpackage (assuming there is only one)
|
||||
DEB_FILE=$(find "$JPACKAGE_DIR" -type f -name "*.deb" -print -quit)
|
||||
|
||||
# Check if a .deb file was found
|
||||
if [ -z "$DEB_FILE" ]; then
|
||||
echo "Error: No .deb file found in $JPACKAGE_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract the filename from the path for later use
|
||||
DEB_FILENAME=$(basename "$DEB_FILE")
|
||||
|
||||
echo "Found .deb file: $DEB_FILENAME"
|
||||
|
||||
# Create a temp directory inside build to avoid file conflicts
|
||||
mkdir -p "$TEMP_DIR"
|
||||
cd "$TEMP_DIR"
|
||||
|
||||
# Extract the .deb file contents
|
||||
ar x "../../$DEB_FILE"
|
||||
|
||||
# Decompress zst files to tar
|
||||
unzstd control.tar.zst
|
||||
unzstd data.tar.zst
|
||||
|
||||
# Compress tar files to xz
|
||||
xz -c control.tar > control.tar.xz
|
||||
xz -c data.tar > data.tar.xz
|
||||
|
||||
# Remove the original .deb file
|
||||
rm "../../$DEB_FILE"
|
||||
|
||||
# Create the new .deb file with xz compression in the original location
|
||||
ar cr "../../$DEB_FILE" debian-binary control.tar.xz data.tar.xz
|
||||
|
||||
# Clean up temp files
|
||||
cd ../..
|
||||
rm -rf "$TEMP_DIR"
|
||||
|
||||
echo "Repackaging complete: $DEB_FILENAME"
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.1.4</string>
|
||||
<string>2.2.2</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<!-- See https://developer.apple.com/app-store/categories/ for list of AppStore categories -->
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import java.util.*;
|
|||
public class SparrowWallet {
|
||||
public static final String APP_ID = "sparrow";
|
||||
public static final String APP_NAME = "Sparrow";
|
||||
public static final String APP_VERSION = "2.1.4";
|
||||
public static final String APP_VERSION = "2.2.2";
|
||||
public static final String APP_VERSION_SUFFIX = "";
|
||||
public static final String APP_HOME_PROPERTY = "sparrow.home";
|
||||
public static final String NETWORK_ENV_PROPERTY = "SPARROW_NETWORK";
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ package com.sparrowwallet.sparrow.control;
|
|||
import com.sparrowwallet.drongo.Network;
|
||||
import com.sparrowwallet.drongo.protocol.Transaction;
|
||||
import com.sparrowwallet.sparrow.BlockSummary;
|
||||
import com.sparrowwallet.sparrow.io.Config;
|
||||
import com.sparrowwallet.sparrow.net.FeeRatesSource;
|
||||
import javafx.animation.KeyFrame;
|
||||
import javafx.animation.KeyValue;
|
||||
import javafx.animation.Timeline;
|
||||
|
|
@ -15,6 +17,7 @@ import javafx.scene.text.FontWeight;
|
|||
import javafx.scene.text.Text;
|
||||
import javafx.scene.text.TextFlow;
|
||||
import javafx.util.Duration;
|
||||
import org.girod.javafx.svgimage.SVGImage;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
|
@ -26,12 +29,13 @@ public class BlockCube extends Group {
|
|||
public static final double CUBE_SIZE = 60;
|
||||
|
||||
private final IntegerProperty weightProperty = new SimpleIntegerProperty(0);
|
||||
private final DoubleProperty medianFeeProperty = new SimpleDoubleProperty(-1.0d);
|
||||
private final DoubleProperty medianFeeProperty = new SimpleDoubleProperty(-Double.MAX_VALUE);
|
||||
private final IntegerProperty heightProperty = new SimpleIntegerProperty(0);
|
||||
private final IntegerProperty txCountProperty = new SimpleIntegerProperty(0);
|
||||
private final LongProperty timestampProperty = new SimpleLongProperty(System.currentTimeMillis());
|
||||
private final StringProperty elapsedProperty = new SimpleStringProperty("");
|
||||
private final BooleanProperty confirmedProperty = new SimpleBooleanProperty(false);
|
||||
private final ObjectProperty<FeeRatesSource> feeRatesSource = new SimpleObjectProperty<>(null);
|
||||
|
||||
private Polygon front;
|
||||
private Rectangle unusedArea;
|
||||
|
|
@ -43,10 +47,12 @@ public class BlockCube extends Group {
|
|||
private final TextFlow medianFeeTextFlow = new TextFlow();
|
||||
private final Text txCountText = new Text();
|
||||
private final Text elapsedText = new Text();
|
||||
private final Group feeRateIcon = new Group();
|
||||
|
||||
public BlockCube(Integer weight, Double medianFee, Integer height, Integer txCount, Long timestamp, boolean confirmed) {
|
||||
getStyleClass().addAll("block-" + Network.getCanonical().getName(), "block-cube");
|
||||
this.confirmedProperty.set(confirmed);
|
||||
this.feeRatesSource.set(Config.get().getFeeRatesSource());
|
||||
|
||||
this.weightProperty.addListener((_, _, _) -> {
|
||||
if(front != null) {
|
||||
|
|
@ -54,10 +60,11 @@ public class BlockCube extends Group {
|
|||
}
|
||||
});
|
||||
this.medianFeeProperty.addListener((_, _, newValue) -> {
|
||||
medianFeeText.setText("~" + Math.round(Math.max(newValue.doubleValue(), 1.0d)));
|
||||
unitsText.setText(" s/vb");
|
||||
medianFeeText.setText(newValue.doubleValue() < 0.0d ? "" : "~" + Math.round(Math.max(newValue.doubleValue(), 1.0d)));
|
||||
unitsText.setText(newValue.doubleValue() < 0.0d ? "" : " s/vb");
|
||||
double medianFeeWidth = TextUtils.computeTextWidth(medianFeeText.getFont(), medianFeeText.getText(), 0.0d);
|
||||
double unitsWidth = TextUtils.computeTextWidth(unitsText.getFont(), unitsText.getText(), 0.0d);
|
||||
medianFeeTextFlow.setTranslateX((CUBE_SIZE - (medianFeeText.getLayoutBounds().getWidth() + unitsWidth)) / 2);
|
||||
medianFeeTextFlow.setTranslateX((CUBE_SIZE - (medianFeeWidth + unitsWidth)) / 2);
|
||||
});
|
||||
this.txCountProperty.addListener((_, _, newValue) -> {
|
||||
txCountText.setText(newValue.intValue() == 0 ? "" : newValue + " txes");
|
||||
|
|
@ -79,6 +86,11 @@ public class BlockCube extends Group {
|
|||
updateFill();
|
||||
}
|
||||
});
|
||||
this.feeRatesSource.addListener((_, _, _) -> {
|
||||
if(front != null) {
|
||||
updateFill();
|
||||
}
|
||||
});
|
||||
this.medianFeeText.textProperty().addListener((_, _, _) -> {
|
||||
pulse();
|
||||
});
|
||||
|
|
@ -145,12 +157,15 @@ public class BlockCube extends Group {
|
|||
txCountText.setX((CUBE_SIZE - txCountText.getLayoutBounds().getWidth()) / 2);
|
||||
txCountText.setY(34);
|
||||
|
||||
feeRateIcon.setTranslateX(((CUBE_SIZE * 0.7) - 14) / 2);
|
||||
feeRateIcon.setTranslateY(-36);
|
||||
|
||||
elapsedText.getStyleClass().add("block-text");
|
||||
elapsedText.setFont(new Font(10));
|
||||
elapsedText.setX((CUBE_SIZE - elapsedText.getLayoutBounds().getWidth()) / 2);
|
||||
elapsedText.setY(50);
|
||||
|
||||
getChildren().addAll(frontFaceGroup, top, left, heightText, medianFeeTextFlow, txCountText, elapsedText);
|
||||
getChildren().addAll(frontFaceGroup, top, left, heightText, medianFeeTextFlow, txCountText, feeRateIcon, elapsedText);
|
||||
}
|
||||
|
||||
private void updateFill() {
|
||||
|
|
@ -167,6 +182,7 @@ public class BlockCube extends Group {
|
|||
usedArea.setHeight(CUBE_SIZE - startYAbsolute);
|
||||
usedArea.setVisible(true);
|
||||
heightText.setVisible(true);
|
||||
feeRateIcon.getChildren().clear();
|
||||
} else {
|
||||
getStyleClass().removeAll("block-confirmed");
|
||||
if(!getStyleClass().contains("block-unconfirmed")) {
|
||||
|
|
@ -175,6 +191,14 @@ public class BlockCube extends Group {
|
|||
usedArea.setVisible(false);
|
||||
unusedArea.setStyle("-fx-fill: " + getFeeRateStyleName() + ";");
|
||||
heightText.setVisible(false);
|
||||
if(feeRatesSource.get() != null) {
|
||||
SVGImage svgImage = feeRatesSource.get().getSVGImage();
|
||||
if(svgImage != null) {
|
||||
feeRateIcon.getChildren().setAll(feeRatesSource.get().getSVGImage());
|
||||
} else {
|
||||
feeRateIcon.getChildren().clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -324,8 +348,20 @@ public class BlockCube extends Group {
|
|||
confirmedProperty.set(confirmed);
|
||||
}
|
||||
|
||||
public FeeRatesSource getFeeRatesSource() {
|
||||
return feeRatesSource.get();
|
||||
}
|
||||
|
||||
public ObjectProperty<FeeRatesSource> feeRatesSourceProperty() {
|
||||
return feeRatesSource;
|
||||
}
|
||||
|
||||
public void setFeeRatesSource(FeeRatesSource feeRatesSource) {
|
||||
this.feeRatesSource.set(feeRatesSource);
|
||||
}
|
||||
|
||||
public static BlockCube fromBlockSummary(BlockSummary blockSummary) {
|
||||
return new BlockCube(blockSummary.getWeight().orElse(0), blockSummary.getMedianFee().orElse(1.0d), blockSummary.getHeight(),
|
||||
return new BlockCube(blockSummary.getWeight().orElse(0), blockSummary.getMedianFee().orElse(-1.0d), blockSummary.getHeight(),
|
||||
blockSummary.getTransactionCount().orElse(0), blockSummary.getTimestamp().getTime(), true);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,15 @@
|
|||
package com.sparrowwallet.sparrow.control;
|
||||
|
||||
import com.sparrowwallet.sparrow.BlockSummary;
|
||||
import com.sparrowwallet.sparrow.io.Config;
|
||||
import com.sparrowwallet.sparrow.net.FeeRatesSource;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.rxjavafx.schedulers.JavaFxScheduler;
|
||||
import javafx.animation.TranslateTransition;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.shape.Line;
|
||||
import javafx.scene.shape.Rectangle;
|
||||
|
|
@ -14,8 +17,12 @@ import javafx.util.Duration;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.sparrowwallet.sparrow.AppServices.TARGET_BLOCKS_RANGE;
|
||||
import static com.sparrowwallet.sparrow.control.BlockCube.CUBE_SIZE;
|
||||
|
||||
public class RecentBlocksView extends Pane {
|
||||
private static final double CUBE_SPACING = 100;
|
||||
private static final double ANIMATION_DURATION_MILLIS = 1000;
|
||||
|
|
@ -24,6 +31,7 @@ public class RecentBlocksView extends Pane {
|
|||
private final CompositeDisposable disposables = new CompositeDisposable();
|
||||
|
||||
private final ObjectProperty<List<BlockCube>> cubesProperty = new SimpleObjectProperty<>(new ArrayList<>());
|
||||
private final Tooltip tooltip = new Tooltip();
|
||||
|
||||
public RecentBlocksView() {
|
||||
cubesProperty.addListener((_, _, newValue) -> {
|
||||
|
|
@ -41,6 +49,16 @@ public class RecentBlocksView extends Pane {
|
|||
cube.setElapsed(BlockCube.getElapsed(cube.getTimestamp()));
|
||||
}
|
||||
}));
|
||||
|
||||
updateFeeRatesSource(Config.get().getFeeRatesSource());
|
||||
Tooltip.install(this, tooltip);
|
||||
}
|
||||
|
||||
public void updateFeeRatesSource(FeeRatesSource feeRatesSource) {
|
||||
tooltip.setText("Fee rate estimate from " + feeRatesSource.getDescription());
|
||||
if(getCubes() != null && !getCubes().isEmpty()) {
|
||||
getCubes().getFirst().setFeeRatesSource(feeRatesSource);
|
||||
}
|
||||
}
|
||||
|
||||
public void drawView() {
|
||||
|
|
@ -54,7 +72,7 @@ public class RecentBlocksView extends Pane {
|
|||
}
|
||||
|
||||
private void createSeparator() {
|
||||
Line separator = new Line(SEPARATOR_X, -9, SEPARATOR_X, 80);
|
||||
Line separator = new Line(SEPARATOR_X, -9, SEPARATOR_X, CUBE_SIZE);
|
||||
separator.getStyleClass().add("blocks-separator");
|
||||
separator.getStrokeDashArray().addAll(5.0, 5.0); // Create dotted line pattern
|
||||
separator.setStrokeWidth(1.0);
|
||||
|
|
@ -73,14 +91,14 @@ public class RecentBlocksView extends Pane {
|
|||
if(latestTip > knownTip) {
|
||||
addNewBlock(latestBlocks, currentFeeRate);
|
||||
} else {
|
||||
for(int i = 1; i < getCubes().size() && i < latestBlocks.size(); i++) {
|
||||
for(int i = 1; i < getCubes().size() && i <= latestBlocks.size(); i++) {
|
||||
BlockCube blockCube = getCubes().get(i);
|
||||
BlockSummary latestBlock = latestBlocks.get(i);
|
||||
BlockSummary latestBlock = latestBlocks.get(i - 1);
|
||||
blockCube.setConfirmed(true);
|
||||
blockCube.setHeight(latestBlock.getHeight());
|
||||
blockCube.setTimestamp(latestBlock.getTimestamp().getTime());
|
||||
blockCube.setWeight(latestBlock.getWeight().orElse(0));
|
||||
blockCube.setMedianFee(latestBlock.getMedianFee().orElse(0.0d));
|
||||
blockCube.setMedianFee(latestBlock.getMedianFee().orElse(-1.0d));
|
||||
blockCube.setTxCount(latestBlock.getTransactionCount().orElse(0));
|
||||
}
|
||||
updateFeeRate(currentFeeRate);
|
||||
|
|
@ -100,7 +118,7 @@ public class RecentBlocksView extends Pane {
|
|||
blockCube.setHeight(latestBlock.getHeight());
|
||||
blockCube.setTimestamp(latestBlock.getTimestamp().getTime());
|
||||
blockCube.setWeight(latestBlock.getWeight().orElse(0));
|
||||
blockCube.setMedianFee(latestBlock.getMedianFee().orElse(0.0d));
|
||||
blockCube.setMedianFee(latestBlock.getMedianFee().orElse(-1.0d));
|
||||
blockCube.setTxCount(latestBlock.getTransactionCount().orElse(0));
|
||||
}
|
||||
|
||||
|
|
@ -120,6 +138,12 @@ public class RecentBlocksView extends Pane {
|
|||
}
|
||||
}
|
||||
|
||||
public void updateFeeRate(Map<Integer, Double> targetBlockFeeRates) {
|
||||
int defaultTarget = TARGET_BLOCKS_RANGE.get((TARGET_BLOCKS_RANGE.size() / 2) - 1);
|
||||
Double defaultRate = targetBlockFeeRates.get(defaultTarget);
|
||||
updateFeeRate(defaultRate);
|
||||
}
|
||||
|
||||
public void updateFeeRate(Double currentFeeRate) {
|
||||
if(!getCubes().isEmpty()) {
|
||||
BlockCube firstCube = getCubes().getFirst();
|
||||
|
|
|
|||
|
|
@ -227,9 +227,9 @@ public class TransactionDiagram extends GridPane {
|
|||
getChildren().clear();
|
||||
getChildren().addAll(inputsTypePane, inputsPane, inputsLinesPane, txPane, outputsLinesPane, outputsPane);
|
||||
|
||||
List<Payment> defaultPayments = getDefaultPayments();
|
||||
if(!isFinal() && defaultPayments.size() > 1) {
|
||||
Pane totalsPane = getTotalsPane(defaultPayments);
|
||||
List<Payment> userPayments = getUserPayments();
|
||||
if(!isFinal() && userPayments.size() > 1) {
|
||||
Pane totalsPane = getTotalsPane(userPayments);
|
||||
GridPane.setConstraints(totalsPane, 2, 0, 3, 1);
|
||||
getChildren().add(totalsPane);
|
||||
}
|
||||
|
|
@ -621,8 +621,8 @@ public class TransactionDiagram extends GridPane {
|
|||
}
|
||||
}
|
||||
|
||||
private List<Payment> getDefaultPayments() {
|
||||
return walletTx.getPayments().stream().filter(payment -> payment.getType() == Payment.Type.DEFAULT).toList();
|
||||
private List<Payment> getUserPayments() {
|
||||
return walletTx.getPayments().stream().filter(payment -> payment.getType() == Payment.Type.DEFAULT || payment.getType() == Payment.Type.ANCHOR).toList();
|
||||
}
|
||||
|
||||
private Pane getOutputsLines(List<Payment> displayedPayments) {
|
||||
|
|
@ -848,18 +848,18 @@ public class TransactionDiagram extends GridPane {
|
|||
return txPane;
|
||||
}
|
||||
|
||||
private Pane getTotalsPane(List<Payment> defaultPayments) {
|
||||
private Pane getTotalsPane(List<Payment> userPayments) {
|
||||
VBox totalsBox = new VBox();
|
||||
totalsBox.setPadding(new Insets(0, 0, 15, 0));
|
||||
totalsBox.setAlignment(Pos.CENTER);
|
||||
|
||||
long amount = defaultPayments.stream().mapToLong(Payment::getAmount).sum();
|
||||
long amount = userPayments.stream().mapToLong(Payment::getAmount).sum();
|
||||
|
||||
HBox coinLabelBox = new HBox();
|
||||
coinLabelBox.setAlignment(Pos.CENTER);
|
||||
CoinLabel totalCoinLabel = new CoinLabel();
|
||||
totalCoinLabel.setValue(amount);
|
||||
coinLabelBox.getChildren().addAll(totalCoinLabel, new Label(" in "), new Label(Long.toString(defaultPayments.size())), new Label(" payments"));
|
||||
coinLabelBox.getChildren().addAll(totalCoinLabel, new Label(" in "), new Label(Long.toString(userPayments.size())), new Label(" payments"));
|
||||
totalsBox.getChildren().addAll(createSpacer(), coinLabelBox);
|
||||
|
||||
CurrencyRate currencyRate = AppServices.getFiatCurrencyExchangeRate();
|
||||
|
|
|
|||
|
|
@ -1,12 +1,22 @@
|
|||
package com.sparrowwallet.sparrow.net;
|
||||
|
||||
import com.sparrowwallet.sparrow.AppServices;
|
||||
import com.sparrowwallet.sparrow.io.Server;
|
||||
import org.girod.javafx.svgimage.SVGImage;
|
||||
import org.girod.javafx.svgimage.SVGLoader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Locale;
|
||||
|
||||
public enum BlockExplorer {
|
||||
MEMPOOL_SPACE("https://mempool.space"),
|
||||
BLOCKSTREAM_INFO("https://blockstream.info"),
|
||||
NONE("http://none");
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(BlockExplorer.class);
|
||||
|
||||
private final Server server;
|
||||
|
||||
BlockExplorer(String url) {
|
||||
|
|
@ -16,4 +26,17 @@ public enum BlockExplorer {
|
|||
public Server getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public static SVGImage getSVGImage(Server server) {
|
||||
try {
|
||||
URL url = AppServices.class.getResource("/image/blockexplorer/" + server.getHost().toLowerCase(Locale.ROOT) + "-icon.svg");
|
||||
if(url != null) {
|
||||
return SVGLoader.load(url);
|
||||
}
|
||||
} catch(Exception e) {
|
||||
log.error("Could not load block explorer image for " + server.getHost());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ public class ElectrumServer {
|
|||
return 0;
|
||||
});
|
||||
|
||||
return txos.stream().map(txo -> new ScriptHashTx(txo.getHeight(), txo.getHashAsString(), txo.getFee())).toList();
|
||||
return txos.stream().map(txo -> new ScriptHashTx(txo.getHeight(), txo.getHashAsString(), txo.getFee() == null ? 0 : txo.getFee())).toList();
|
||||
}
|
||||
|
||||
private static String getScriptHashStatus(List<ScriptHashTx> scriptHashTxes) {
|
||||
|
|
@ -439,7 +439,7 @@ public class ElectrumServer {
|
|||
blkTx.getTransaction().getInputs().stream().map(txInput -> getPrevOutput(wallet, txInput))
|
||||
.filter(Objects::nonNull).map(ElectrumServer::getScriptHash).anyMatch(scriptHash::equals)) {
|
||||
List<ScriptHashTx> scriptHashTxes = new ArrayList<>(getScriptHashes(scriptHash, node));
|
||||
scriptHashTxes.add(new ScriptHashTx(0, txid.toString(), blkTx.getFee()));
|
||||
scriptHashTxes.add(new ScriptHashTx(0, txid.toString(), blkTx.getFee() == null ? 0 : blkTx.getFee()));
|
||||
|
||||
String status = getScriptHashStatus(scriptHashTxes);
|
||||
if(Objects.equals(status, statuses.getLast())) {
|
||||
|
|
|
|||
|
|
@ -9,9 +9,12 @@ import javafx.concurrent.ScheduledService;
|
|||
import javafx.concurrent.Service;
|
||||
import javafx.concurrent.Task;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.girod.javafx.svgimage.SVGImage;
|
||||
import org.girod.javafx.svgimage.SVGLoader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.net.URL;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Instant;
|
||||
|
|
@ -297,6 +300,19 @@ public enum ExchangeSource {
|
|||
return name;
|
||||
}
|
||||
|
||||
public SVGImage getSVGImage() {
|
||||
try {
|
||||
URL url = AppServices.class.getResource("/image/exchangesource/" + name.toLowerCase(Locale.ROOT) + "-icon.svg");
|
||||
if(url != null) {
|
||||
return SVGLoader.load(url);
|
||||
}
|
||||
} catch(Exception e) {
|
||||
log.error("Could not load exchange source image for " + name);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class CurrenciesService extends Service<List<Currency>> {
|
||||
private final ExchangeSource exchangeSource;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,9 +7,12 @@ import com.sparrowwallet.drongo.wallet.BlockTransaction;
|
|||
import com.sparrowwallet.drongo.wallet.BlockTransactionHash;
|
||||
import com.sparrowwallet.sparrow.AppServices;
|
||||
import com.sparrowwallet.sparrow.BlockSummary;
|
||||
import org.girod.javafx.svgimage.SVGImage;
|
||||
import org.girod.javafx.svgimage.SVGLoader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
|
||||
public enum FeeRatesSource {
|
||||
|
|
@ -275,6 +278,27 @@ public enum FeeRatesSource {
|
|||
return name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return switch(this) {
|
||||
case ELECTRUM_SERVER -> "server";
|
||||
case MINIMUM -> "settings";
|
||||
default -> getName().toLowerCase(Locale.ROOT);
|
||||
};
|
||||
}
|
||||
|
||||
public SVGImage getSVGImage() {
|
||||
try {
|
||||
URL url = AppServices.class.getResource("/image/feeratesource/" + getDescription() + "-icon.svg");
|
||||
if(url != null) {
|
||||
return SVGLoader.load(url);
|
||||
}
|
||||
} catch(Exception e) {
|
||||
log.error("Could not load fee rates source image for " + name);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected record ThreeTierRates(Double fastestFee, Double halfHourFee, Double hourFee, Double minimumFee) {}
|
||||
|
||||
private record OxtRates(OxtRatesData[] data) {}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,8 @@ public class GeneralSettingsController extends SettingsDetailController {
|
|||
config.setFeeRatesSource(feeRatesSource.getValue());
|
||||
}
|
||||
|
||||
feeRatesSource.setCellFactory(_ -> new FeeRatesSourceListCell());
|
||||
feeRatesSource.setButtonCell(feeRatesSource.getCellFactory().call(null));
|
||||
feeRatesSource.valueProperty().addListener((observable, oldValue, newValue) -> {
|
||||
config.setFeeRatesSource(newValue);
|
||||
EventManager.get().post(new FeeRatesSourceChangedEvent(newValue));
|
||||
|
|
@ -96,25 +98,8 @@ public class GeneralSettingsController extends SettingsDetailController {
|
|||
currenciesLoadWarning.setVisible(false);
|
||||
|
||||
blockExplorers.setItems(getBlockExplorerList());
|
||||
blockExplorers.setConverter(new StringConverter<>() {
|
||||
@Override
|
||||
public String toString(Server server) {
|
||||
if(server == null || server == BlockExplorer.NONE.getServer()) {
|
||||
return "None";
|
||||
}
|
||||
|
||||
if(server == CUSTOM_BLOCK_EXPLORER) {
|
||||
return "Custom...";
|
||||
}
|
||||
|
||||
return server.getHost();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Server fromString(String string) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
blockExplorers.setCellFactory(_ -> new BlockExplorerListCell());
|
||||
blockExplorers.setButtonCell(blockExplorers.getCellFactory().call(null));
|
||||
blockExplorers.valueProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if(newValue != null) {
|
||||
if(newValue == CUSTOM_BLOCK_EXPLORER) {
|
||||
|
|
@ -258,14 +243,50 @@ public class GeneralSettingsController extends SettingsDetailController {
|
|||
fiatCurrency.valueProperty().addListener(fiatCurrencyListener);
|
||||
}
|
||||
|
||||
private static class FeeRatesSourceListCell extends ListCell<FeeRatesSource> {
|
||||
@Override
|
||||
protected void updateItem(FeeRatesSource item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if(empty || item == null) {
|
||||
setText(null);
|
||||
setGraphic(null);
|
||||
} else {
|
||||
setText(item.toString());
|
||||
setGraphic(item.getSVGImage());
|
||||
setGraphicTextGap(8.0d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class BlockExplorerListCell extends ListCell<Server> {
|
||||
@Override
|
||||
protected void updateItem(Server server, boolean empty) {
|
||||
super.updateItem(server, empty);
|
||||
if(empty || server == null || server == BlockExplorer.NONE.getServer()) {
|
||||
setText("None");
|
||||
setGraphic(null);
|
||||
} else if(server == CUSTOM_BLOCK_EXPLORER) {
|
||||
setText("Custom...");
|
||||
setGraphic(null);
|
||||
} else {
|
||||
setText(server.getHost());
|
||||
setGraphic(BlockExplorer.getSVGImage(server));
|
||||
setGraphicTextGap(8.0d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ExchangeSourceButtonCell extends ListCell<ExchangeSource> {
|
||||
@Override
|
||||
protected void updateItem(ExchangeSource exchangeSource, boolean empty) {
|
||||
super.updateItem(exchangeSource, empty);
|
||||
if(exchangeSource == null || empty) {
|
||||
setText("");
|
||||
setGraphic(null);
|
||||
} else {
|
||||
setText(exchangeSource.getName());
|
||||
setGraphic(exchangeSource.getSVGImage());
|
||||
setGraphicTextGap(8.0d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -276,12 +297,15 @@ public class GeneralSettingsController extends SettingsDetailController {
|
|||
super.updateItem(exchangeSource, empty);
|
||||
if(exchangeSource == null || empty) {
|
||||
setText("");
|
||||
setGraphic(null);
|
||||
} else {
|
||||
String text = exchangeSource.getName();
|
||||
if(exchangeSource.getDescription() != null && !exchangeSource.getDescription().isEmpty()) {
|
||||
text += " (" + exchangeSource.getDescription() + ")";
|
||||
}
|
||||
setText(text);
|
||||
setGraphic(exchangeSource.getSVGImage());
|
||||
setGraphicTextGap(8.0d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1411,6 +1411,7 @@ public class SendController extends WalletFormController implements Initializabl
|
|||
setFeeRatePriority(getFeeRangeRate());
|
||||
}
|
||||
feeRange.updateTrackHighlight();
|
||||
recentBlocksView.updateFeeRate(event.getTargetBlockFeeRates());
|
||||
|
||||
if(updateDefaultFeeRate) {
|
||||
if(getFeeRate() != null && Long.valueOf((long)getFallbackFeeRate()).equals(getFeeRate().longValue())) {
|
||||
|
|
@ -1600,6 +1601,11 @@ public class SendController extends WalletFormController implements Initializabl
|
|||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void feeRateSourceChanged(FeeRatesSourceChangedEvent event) {
|
||||
recentBlocksView.updateFeeRatesSource(event.getFeeRateSource());
|
||||
}
|
||||
|
||||
private class PrivacyAnalysisTooltip extends VBox {
|
||||
private final List<Label> analysisLabels = new ArrayList<>();
|
||||
|
||||
|
|
@ -1625,7 +1631,9 @@ public class SendController extends WalletFormController implements Initializabl
|
|||
} else if(payjoinPresent) {
|
||||
addLabel("Cannot fake coinjoin due to payjoin", getInfoGlyph());
|
||||
} else {
|
||||
if(utxoSelectorProperty().get() != null && !(utxoSelectorProperty().get() instanceof MaxUtxoSelector)) {
|
||||
if(utxoSelectorProperty().get() instanceof MaxUtxoSelector) {
|
||||
addLabel("Cannot fake coinjoin with max amount selected", getInfoGlyph());
|
||||
} else if(utxoSelectorProperty().get() != null) {
|
||||
addLabel("Cannot fake coinjoin due to coin control", getInfoGlyph());
|
||||
} else {
|
||||
addLabel("Cannot fake coinjoin due to insufficient funds", getInfoGlyph());
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14px" height="14px" viewBox="0 0 14 14" version="1.1">
|
||||
<g id="surface1">
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(54.11765%,54.11765%,54.11765%);fill-opacity:1;" d="M 9.695312 9.898438 C 9.050781 10.582031 8.230469 10.972656 7.386719 11.074219 L 6.589844 12.925781 C 8.144531 13.027344 9.738281 12.453125 10.929688 11.199219 C 13.007812 9.007812 13.121094 5.527344 11.269531 3.195312 L 10.027344 4.5 C 11.203125 6.109375 11.09375 8.429688 9.695312 9.902344 Z M 9.695312 9.898438 "/>
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(68.235295%,68.235295%,68.235295%);fill-opacity:1;" d="M 3.148438 6.117188 C 3.304688 5.375 3.652344 4.675781 4.195312 4.101562 C 5.605469 2.609375 7.84375 2.507812 9.367188 3.792969 L 10.605469 2.488281 C 8.394531 0.488281 5.058594 0.59375 2.964844 2.800781 C 1.902344 3.921875 1.355469 5.375 1.320312 6.839844 Z M 3.148438 6.117188 "/>
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 1.691406 7.960938 L 4.695312 9 L 5.511719 12.414062 L 8.371094 5.546875 Z M 1.691406 7.960938 "/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14px" height="14px" viewBox="0 0 14 14" version="1.1">
|
||||
<defs>
|
||||
<linearGradient id="linear0" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="1" y2="0" gradientTransform="matrix(0,10.538675,-10.538675,0,6.999808,4.639967)">
|
||||
<stop offset="0" style="stop-color:rgb(42.941176%,42.941176%,42.941176%);stop-opacity:0.8;"/>
|
||||
<stop offset="0.998812" style="stop-color:rgb(96.078431%,96.078431%,96.078431%);stop-opacity:0.8;"/>
|
||||
</linearGradient>
|
||||
<filter id="alpha" filterUnits="objectBoundingBox" x="0%" y="0%" width="100%" height="100%">
|
||||
<feColorMatrix type="matrix" in="SourceGraphic" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
|
||||
</filter>
|
||||
<mask id="mask0">
|
||||
<g filter="url(#alpha)">
|
||||
<rect x="0" y="0" width="14" height="14" style="fill:rgb(0%,0%,0%);fill-opacity:0.301961;stroke:none;"/>
|
||||
</g>
|
||||
</mask>
|
||||
<clipPath id="clip1">
|
||||
<rect x="0" y="0" width="15" height="15"/>
|
||||
</clipPath>
|
||||
<g id="surface5" clip-path="url(#clip1)">
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:0.6;" d="M 11.160156 11.003906 C 11.160156 11.171875 11.046875 11.304688 10.90625 11.304688 L 9.492188 11.304688 C 9.351562 11.304688 9.238281 11.171875 9.238281 11.003906 L 9.238281 2.996094 C 9.238281 2.828125 9.351562 2.695312 9.492188 2.695312 L 10.90625 2.695312 C 11.046875 2.695312 11.160156 2.828125 11.160156 2.996094 Z M 11.160156 11.003906 "/>
|
||||
</g>
|
||||
</defs>
|
||||
<g id="surface1">
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(20.392157%,20.392157%,20.392157%);fill-opacity:0.9;" d="M 12.453125 11.101562 C 12.453125 11.855469 11.847656 12.460938 11.09375 12.460938 L 2.898438 12.460938 C 2.148438 12.460938 1.542969 11.855469 1.542969 11.101562 L 1.542969 2.898438 C 1.542969 2.144531 2.152344 1.539062 2.898438 1.539062 L 11.09375 1.539062 C 11.847656 1.539062 12.453125 2.144531 12.453125 2.898438 Z M 12.453125 11.101562 "/>
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:url(#linear0);" d="M 1.542969 7.011719 L 1.542969 11.101562 C 1.542969 11.855469 2.152344 12.460938 2.90625 12.460938 L 11.09375 12.460938 C 11.847656 12.460938 12.457031 11.855469 12.457031 11.101562 L 12.457031 7.011719 Z M 1.542969 7.011719 "/>
|
||||
<use xlink:href="#surface5" mask="url(#mask0)"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14px" height="14px" viewBox="0 0 14 14" version="1.1">
|
||||
<g id="surface1">
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:#7a7a7a;fill-opacity:1;" d="M 6.996094 1.132812 C 10.234375 1.132812 12.859375 3.757812 12.859375 6.996094 C 12.859375 10.234375 10.234375 12.859375 6.996094 12.859375 C 3.757812 12.859375 1.132812 10.234375 1.132812 6.996094 C 1.132812 3.757812 3.757812 1.132812 6.996094 1.132812 Z M 6.996094 1.132812 "/>
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 6.996094 9.054688 C 5.859375 9.054688 4.9375 8.132812 4.9375 6.996094 C 4.9375 5.859375 5.859375 4.933594 6.996094 4.933594 C 8.015625 4.933594 8.863281 5.675781 9.027344 6.652344 L 11.101562 6.652344 C 10.925781 4.535156 9.15625 2.871094 6.996094 2.871094 C 4.71875 2.871094 2.871094 4.71875 2.871094 6.996094 C 2.871094 9.269531 4.71875 11.117188 6.996094 11.117188 C 9.15625 11.117188 10.925781 9.453125 11.101562 7.339844 L 9.023438 7.339844 C 8.863281 8.3125 8.015625 9.054688 6.996094 9.054688 Z M 6.996094 9.054688 "/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
29
src/main/resources/image/exchangesource/coingecko-icon.svg
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14px" height="14px" viewBox="0 0 14 14" version="1.1">
|
||||
<defs>
|
||||
<clipPath id="clip1">
|
||||
<path d="M 1.398438 1.339844 L 12.601562 1.339844 L 12.601562 12.660156 L 1.398438 12.660156 Z M 1.398438 1.339844 "/>
|
||||
</clipPath>
|
||||
<clipPath id="clip2">
|
||||
<path d="M 2 3 L 12 3 L 12 12.660156 L 2 12.660156 Z M 2 3 "/>
|
||||
</clipPath>
|
||||
<clipPath id="clip3">
|
||||
<path d="M 2 6 L 12 6 L 12 12.660156 L 2 12.660156 Z M 2 6 "/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g id="surface1">
|
||||
<g clip-path="url(#clip1)" clip-rule="nonzero">
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(77.254903%,77.254903%,77.254903%);fill-opacity:1;" d="M 12.601562 6.957031 C 12.613281 10.070312 10.117188 12.605469 7.027344 12.621094 C 3.933594 12.636719 1.414062 10.121094 1.398438 7.007812 C 1.386719 3.890625 3.882812 1.355469 6.976562 1.339844 C 10.066406 1.328125 12.585938 3.839844 12.601562 6.957031 Z M 12.601562 6.957031 "/>
|
||||
</g>
|
||||
<g clip-path="url(#clip2)" clip-rule="nonzero">
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(33.725491%,33.725491%,33.725491%);fill-opacity:1;" d="M 9.839844 4.960938 C 9.433594 4.84375 9.011719 4.675781 8.585938 4.507812 C 8.5625 4.398438 8.464844 4.265625 8.273438 4.101562 C 7.996094 3.855469 7.472656 3.863281 7.019531 3.96875 C 6.519531 3.851562 6.027344 3.808594 5.554688 3.925781 C 1.683594 5 3.878906 7.621094 2.457031 10.253906 C 2.65625 10.6875 4.890625 12.761719 7.992188 12.53125 C 7.992188 12.53125 6.914062 9.921875 9.347656 8.667969 C 11.324219 7.648438 12.75 5.761719 9.839844 4.960938 Z M 9.839844 4.960938 "/>
|
||||
</g>
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 7.289062 5.589844 C 7.289062 6.195312 6.804688 6.679688 6.207031 6.679688 C 5.609375 6.679688 5.125 6.195312 5.125 5.589844 C 5.125 4.988281 5.609375 4.5 6.207031 4.5 C 6.804688 4.5 7.289062 4.988281 7.289062 5.589844 Z M 7.289062 5.589844 "/>
|
||||
<g clip-path="url(#clip3)" clip-rule="nonzero">
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(33.725491%,33.725491%,33.725491%);fill-opacity:1;" d="M 11.195312 7.160156 C 10.316406 7.78125 9.320312 8.253906 7.90625 8.253906 C 7.242188 8.253906 7.109375 7.546875 6.671875 7.894531 C 6.445312 8.074219 5.648438 8.472656 5.015625 8.445312 C 4.375 8.414062 3.359375 8.039062 3.070312 6.679688 C 2.957031 8.039062 2.902344 9.042969 2.394531 10.1875 C 3.636719 12.019531 5.808594 12.929688 7.992188 12.53125 C 7.757812 10.882812 9.191406 9.265625 9.996094 8.4375 C 10.304688 8.125 10.890625 7.613281 11.195312 7.160156 Z M 11.195312 7.160156 "/>
|
||||
</g>
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(5.098039%,7.058824%,9.019608%);fill-opacity:1;" d="M 6.027344 5.582031 C 6.027344 5.09375 6.3125 4.695312 6.664062 4.695312 C 7.011719 4.695312 7.296875 5.09375 7.296875 5.582031 C 7.296875 6.074219 7.011719 6.472656 6.664062 6.472656 C 6.3125 6.472656 6.027344 6.074219 6.027344 5.582031 Z M 6.027344 5.582031 "/>
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(27.450982%,27.450982%,27.450982%);fill-opacity:1;" d="M 6.917969 3.96875 C 7.261719 4.105469 8.527344 4.527344 9.078125 4.695312 C 8.515625 3.765625 7.667969 3.820312 6.917969 3.96875 Z M 6.917969 3.96875 "/>
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 6.664062 5.582031 L 5.898438 5.074219 L 5.898438 6.089844 Z M 6.664062 5.582031 "/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.4 KiB |
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14px" height="14px" viewBox="0 0 14 14" version="1.1">
|
||||
<defs>
|
||||
<linearGradient id="linear0" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="1" y2="0" gradientTransform="matrix(0,10.538675,-10.538675,0,6.999808,4.639967)">
|
||||
<stop offset="0" style="stop-color:rgb(42.941176%,42.941176%,42.941176%);stop-opacity:0.8;"/>
|
||||
<stop offset="0.998812" style="stop-color:rgb(96.078431%,96.078431%,96.078431%);stop-opacity:0.8;"/>
|
||||
</linearGradient>
|
||||
<filter id="alpha" filterUnits="objectBoundingBox" x="0%" y="0%" width="100%" height="100%">
|
||||
<feColorMatrix type="matrix" in="SourceGraphic" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
|
||||
</filter>
|
||||
<mask id="mask0">
|
||||
<g filter="url(#alpha)">
|
||||
<rect x="0" y="0" width="14" height="14" style="fill:rgb(0%,0%,0%);fill-opacity:0.301961;stroke:none;"/>
|
||||
</g>
|
||||
</mask>
|
||||
<clipPath id="clip1">
|
||||
<rect x="0" y="0" width="15" height="15"/>
|
||||
</clipPath>
|
||||
<g id="surface5" clip-path="url(#clip1)">
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:0.6;" d="M 11.160156 11.003906 C 11.160156 11.171875 11.046875 11.304688 10.90625 11.304688 L 9.492188 11.304688 C 9.351562 11.304688 9.238281 11.171875 9.238281 11.003906 L 9.238281 2.996094 C 9.238281 2.828125 9.351562 2.695312 9.492188 2.695312 L 10.90625 2.695312 C 11.046875 2.695312 11.160156 2.828125 11.160156 2.996094 Z M 11.160156 11.003906 "/>
|
||||
</g>
|
||||
</defs>
|
||||
<g id="surface1">
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(20.392157%,20.392157%,20.392157%);fill-opacity:0.9;" d="M 12.453125 11.101562 C 12.453125 11.855469 11.847656 12.460938 11.09375 12.460938 L 2.898438 12.460938 C 2.148438 12.460938 1.542969 11.855469 1.542969 11.101562 L 1.542969 2.898438 C 1.542969 2.144531 2.152344 1.539062 2.898438 1.539062 L 11.09375 1.539062 C 11.847656 1.539062 12.453125 2.144531 12.453125 2.898438 Z M 12.453125 11.101562 "/>
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:url(#linear0);" d="M 1.542969 7.011719 L 1.542969 11.101562 C 1.542969 11.855469 2.152344 12.460938 2.90625 12.460938 L 11.09375 12.460938 C 11.847656 12.460938 12.457031 11.855469 12.457031 11.101562 L 12.457031 7.011719 Z M 1.542969 7.011719 "/>
|
||||
<use xlink:href="#surface5" mask="url(#mask0)"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14px" height="14px" viewBox="0 0 14 14" version="1.1">
|
||||
<defs>
|
||||
<linearGradient id="linear0" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="1" y2="0" gradientTransform="matrix(0,10.538675,-10.538675,0,6.999808,4.639967)">
|
||||
<stop offset="0" style="stop-color:rgb(42.941176%,42.941176%,42.941176%);stop-opacity:0.8;"/>
|
||||
<stop offset="0.998812" style="stop-color:rgb(96.078431%,96.078431%,96.078431%);stop-opacity:0.8;"/>
|
||||
</linearGradient>
|
||||
<filter id="alpha" filterUnits="objectBoundingBox" x="0%" y="0%" width="100%" height="100%">
|
||||
<feColorMatrix type="matrix" in="SourceGraphic" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
|
||||
</filter>
|
||||
<mask id="mask0">
|
||||
<g filter="url(#alpha)">
|
||||
<rect x="0" y="0" width="14" height="14" style="fill:rgb(0%,0%,0%);fill-opacity:0.301961;stroke:none;"/>
|
||||
</g>
|
||||
</mask>
|
||||
<clipPath id="clip1">
|
||||
<rect x="0" y="0" width="15" height="15"/>
|
||||
</clipPath>
|
||||
<g id="surface5" clip-path="url(#clip1)">
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:0.6;" d="M 11.160156 11.003906 C 11.160156 11.171875 11.046875 11.304688 10.90625 11.304688 L 9.492188 11.304688 C 9.351562 11.304688 9.238281 11.171875 9.238281 11.003906 L 9.238281 2.996094 C 9.238281 2.828125 9.351562 2.695312 9.492188 2.695312 L 10.90625 2.695312 C 11.046875 2.695312 11.160156 2.828125 11.160156 2.996094 Z M 11.160156 11.003906 "/>
|
||||
</g>
|
||||
</defs>
|
||||
<g id="surface1">
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(20.392157%,20.392157%,20.392157%);fill-opacity:0.9;" d="M 12.453125 11.101562 C 12.453125 11.855469 11.847656 12.460938 11.09375 12.460938 L 2.898438 12.460938 C 2.148438 12.460938 1.542969 11.855469 1.542969 11.101562 L 1.542969 2.898438 C 1.542969 2.144531 2.152344 1.539062 2.898438 1.539062 L 11.09375 1.539062 C 11.847656 1.539062 12.453125 2.144531 12.453125 2.898438 Z M 12.453125 11.101562 "/>
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:url(#linear0);" d="M 1.542969 7.011719 L 1.542969 11.101562 C 1.542969 11.855469 2.152344 12.460938 2.90625 12.460938 L 11.09375 12.460938 C 11.847656 12.460938 12.457031 11.855469 12.457031 11.101562 L 12.457031 7.011719 Z M 1.542969 7.011719 "/>
|
||||
<use xlink:href="#surface5" mask="url(#mask0)"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
6
src/main/resources/image/feeratesource/server-icon.svg
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14px" height="14px" viewBox="0 0 14 14" version="1.1">
|
||||
<g id="surface1">
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:#a8a8a8;fill-opacity:1;" d="M 11.898438 4.898438 L 2.101562 4.898438 C 1.710938 4.898438 1.398438 4.585938 1.398438 4.199219 L 1.398438 2.800781 C 1.398438 2.414062 1.710938 2.101562 2.101562 2.101562 L 11.898438 2.101562 C 12.289062 2.101562 12.601562 2.414062 12.601562 2.800781 L 12.601562 4.199219 C 12.601562 4.585938 12.289062 4.898438 11.898438 4.898438 Z M 10.851562 2.976562 C 10.558594 2.976562 10.324219 3.210938 10.324219 3.5 C 10.324219 3.789062 10.558594 4.023438 10.851562 4.023438 C 11.140625 4.023438 11.375 3.789062 11.375 3.5 C 11.375 3.210938 11.140625 2.976562 10.851562 2.976562 Z M 9.449219 2.976562 C 9.160156 2.976562 8.925781 3.210938 8.925781 3.5 C 8.925781 3.789062 9.160156 4.023438 9.449219 4.023438 C 9.742188 4.023438 9.976562 3.789062 9.976562 3.5 C 9.976562 3.210938 9.742188 2.976562 9.449219 2.976562 Z M 11.898438 8.398438 L 2.101562 8.398438 C 1.710938 8.398438 1.398438 8.085938 1.398438 7.699219 L 1.398438 6.300781 C 1.398438 5.914062 1.710938 5.601562 2.101562 5.601562 L 11.898438 5.601562 C 12.289062 5.601562 12.601562 5.914062 12.601562 6.300781 L 12.601562 7.699219 C 12.601562 8.085938 12.289062 8.398438 11.898438 8.398438 Z M 10.851562 6.476562 C 10.558594 6.476562 10.324219 6.710938 10.324219 7 C 10.324219 7.289062 10.558594 7.523438 10.851562 7.523438 C 11.140625 7.523438 11.375 7.289062 11.375 7 C 11.375 6.710938 11.140625 6.476562 10.851562 6.476562 Z M 9.449219 6.476562 C 9.160156 6.476562 8.925781 6.710938 8.925781 7 C 8.925781 7.289062 9.160156 7.523438 9.449219 7.523438 C 9.742188 7.523438 9.976562 7.289062 9.976562 7 C 9.976562 6.710938 9.742188 6.476562 9.449219 6.476562 Z M 11.898438 11.898438 L 2.101562 11.898438 C 1.710938 11.898438 1.398438 11.585938 1.398438 11.199219 L 1.398438 9.800781 C 1.398438 9.414062 1.710938 9.101562 2.101562 9.101562 L 11.898438 9.101562 C 12.289062 9.101562 12.601562 9.414062 12.601562 9.800781 L 12.601562 11.199219 C 12.601562 11.585938 12.289062 11.898438 11.898438 11.898438 Z M 10.851562 9.976562 C 10.558594 9.976562 10.324219 10.210938 10.324219 10.5 C 10.324219 10.789062 10.558594 11.023438 10.851562 11.023438 C 11.140625 11.023438 11.375 10.789062 11.375 10.5 C 11.375 10.210938 11.140625 9.976562 10.851562 9.976562 Z M 9.449219 9.976562 C 9.160156 9.976562 8.925781 10.210938 8.925781 10.5 C 8.925781 10.789062 9.160156 11.023438 9.449219 11.023438 C 9.742188 11.023438 9.976562 10.789062 9.976562 10.5 C 9.976562 10.210938 9.742188 9.976562 9.449219 9.976562 Z M 9.449219 9.976562 "/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
6
src/main/resources/image/feeratesource/settings-icon.svg
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14px" height="14px" viewBox="0 0 14 14" version="1.1">
|
||||
<g id="surface1">
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:#a8a8a8;fill-opacity:1;" d="M 12.363281 10.054688 L 9.800781 7.492188 C 9.296875 6.988281 8.539062 6.890625 7.933594 7.191406 L 5.601562 4.859375 L 5.601562 3.5 L 2.800781 1.398438 L 1.402344 2.800781 L 3.5 5.597656 L 4.859375 5.597656 L 7.191406 7.929688 C 6.894531 8.539062 6.988281 9.292969 7.496094 9.800781 L 10.058594 12.359375 C 10.375 12.679688 10.890625 12.679688 11.210938 12.359375 L 12.363281 11.207031 C 12.679688 10.890625 12.679688 10.371094 12.363281 10.054688 Z M 8.65625 6.320312 C 9.277344 6.320312 9.859375 6.5625 10.296875 7 L 10.71875 7.425781 C 11.066406 7.273438 11.394531 7.0625 11.675781 6.777344 C 12.488281 5.96875 12.765625 4.824219 12.507812 3.789062 C 12.457031 3.589844 12.210938 3.523438 12.066406 3.667969 L 10.441406 5.296875 L 8.953125 5.046875 L 8.707031 3.5625 L 10.335938 1.933594 C 10.480469 1.789062 10.410156 1.542969 10.210938 1.492188 C 9.171875 1.238281 8.03125 1.511719 7.222656 2.324219 C 6.597656 2.945312 6.304688 3.769531 6.320312 4.589844 L 8.117188 6.386719 C 8.292969 6.34375 8.476562 6.320312 8.65625 6.320312 Z M 6.382812 8.113281 L 5.144531 6.875 L 1.808594 10.210938 C 1.261719 10.757812 1.261719 11.644531 1.808594 12.191406 C 2.355469 12.738281 3.242188 12.738281 3.789062 12.191406 L 6.492188 9.488281 C 6.328125 9.050781 6.277344 8.578125 6.382812 8.113281 Z M 2.800781 11.722656 C 2.511719 11.722656 2.277344 11.488281 2.277344 11.199219 C 2.277344 10.910156 2.511719 10.675781 2.800781 10.675781 C 3.089844 10.675781 3.324219 10.910156 3.324219 11.199219 C 3.324219 11.488281 3.089844 11.722656 2.800781 11.722656 Z M 2.800781 11.722656 "/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |