Browse Source

Merge pull request #3549 from cryptomator/feature/improve-preferences-contribute-tab

Feature: Optimize 'Support us' Tab in Preferences - Add Supporter Certificate Removal & Improved Layout
mindmonk 7 months ago
parent
commit
978dec64ee

+ 1 - 0
src/main/java/org/cryptomator/ui/common/FxmlFile.java

@@ -45,6 +45,7 @@ public enum FxmlFile {
 	RECOVERYKEY_RESET_PASSWORD("/fxml/recoverykey_reset_password.fxml"), //
 	RECOVERYKEY_RESET_PASSWORD_SUCCESS("/fxml/recoverykey_reset_password_success.fxml"), //
 	RECOVERYKEY_SUCCESS("/fxml/recoverykey_success.fxml"), //
+	REMOVE_CERT("/fxml/remove_cert.fxml"), //
 	REMOVE_VAULT("/fxml/remove_vault.fxml"), //
 	SHARE_VAULT("/fxml/share_vault.fxml"), //
 	UPDATE_REMINDER("/fxml/update_reminder.fxml"), //

+ 2 - 0
src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java

@@ -17,6 +17,7 @@ public enum FontAwesome5Icon {
 	COGS("\uF085"), //
 	COPY("\uF0C5"), //
 	CROWN("\uF521"), //
+	DONATE("\uF4B9"), //
 	EDIT("\uF044"), //
 	EXCHANGE_ALT("\uF362"), //
 	EXCLAMATION("\uF12A"), //
@@ -49,6 +50,7 @@ public enum FontAwesome5Icon {
 	SEARCH("\uF002"), //
 	SHARE("\uF064"), //
 	SPINNER("\uF110"), //
+	SPONSORS("\uF2B5"), //
 	STETHOSCOPE("\uF0f1"), //
 	SYNC("\uF021"), //
 	TIMES("\uF00D"), //

+ 2 - 0
src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java

@@ -14,6 +14,7 @@ import org.cryptomator.ui.lock.LockComponent;
 import org.cryptomator.ui.mainwindow.MainWindowComponent;
 import org.cryptomator.ui.preferences.PreferencesComponent;
 import org.cryptomator.ui.quit.QuitComponent;
+import org.cryptomator.ui.removecert.RemoveCertComponent;
 import org.cryptomator.ui.sharevault.ShareVaultComponent;
 import org.cryptomator.ui.traymenu.TrayMenuComponent;
 import org.cryptomator.ui.unlock.UnlockComponent;
@@ -35,6 +36,7 @@ import java.io.InputStream;
 		HealthCheckComponent.class, //
 		UpdateReminderComponent.class, //
 		DokanySupportEndComponent.class, //
+		RemoveCertComponent.class, //
 		ShareVaultComponent.class})
 abstract class FxApplicationModule {
 

+ 1 - 1
src/main/java/org/cryptomator/ui/preferences/PreferencesComponent.java

@@ -31,7 +31,7 @@ public interface PreferencesComponent {
 		Stage stage = window();
 		stage.setScene(scene().get());
 		stage.setMinWidth(420);
-		stage.setMinHeight(300);
+		stage.setMinHeight(400);
 		stage.show();
 		stage.requestFocus();
 		return stage;

+ 32 - 2
src/main/java/org/cryptomator/ui/preferences/SupporterCertificateController.java

@@ -5,6 +5,7 @@ import org.cryptomator.common.LicenseHolder;
 import org.cryptomator.common.settings.Settings;
 import org.cryptomator.common.settings.UiTheme;
 import org.cryptomator.ui.common.FxController;
+import org.cryptomator.ui.removecert.RemoveCertComponent;
 
 import javax.inject.Inject;
 import javafx.application.Application;
@@ -12,22 +13,31 @@ import javafx.beans.value.ObservableValue;
 import javafx.fxml.FXML;
 import javafx.scene.control.TextArea;
 import javafx.scene.control.TextFormatter;
+import javafx.stage.Stage;
 
 @PreferencesScoped
 public class SupporterCertificateController implements FxController {
 
+	private static final String DONATE_URI = "https://cryptomator.org/donate";
+	private static final String SPONSORS_URI = "https://cryptomator.org/sponsors";
 	private static final String SUPPORTER_URI = "https://store.cryptomator.org/desktop";
 
 	private final Application application;
+	private final Stage window;
 	private final LicenseHolder licenseHolder;
 	private final Settings settings;
-	public TextArea supporterCertificateField;
+	private final RemoveCertComponent.Builder removeCert;
+
+	@FXML
+	private TextArea supporterCertificateField;
 
 	@Inject
-	SupporterCertificateController(Application application, LicenseHolder licenseHolder, Settings settings) {
+	SupporterCertificateController(Application application, @PreferencesWindow Stage window, LicenseHolder licenseHolder, Settings settings, RemoveCertComponent.Builder removeCert) {
 		this.application = application;
+		this.window = window;
 		this.licenseHolder = licenseHolder;
 		this.settings = settings;
+		this.removeCert = removeCert;
 	}
 
 	@FXML
@@ -35,6 +45,11 @@ public class SupporterCertificateController implements FxController {
 		supporterCertificateField.setText(licenseHolder.getLicenseKey().orElse(null));
 		supporterCertificateField.textProperty().addListener(this::registrationKeyChanged);
 		supporterCertificateField.setTextFormatter(new TextFormatter<>(this::removeWhitespaces));
+		settings.licenseKey.addListener((_, _, newValue) -> {
+			if (newValue == null) {
+				supporterCertificateField.setText(null);
+			}
+		});
 	}
 
 	private TextFormatter.Change removeWhitespaces(TextFormatter.Change change) {
@@ -57,6 +72,21 @@ public class SupporterCertificateController implements FxController {
 		application.getHostServices().showDocument(SUPPORTER_URI);
 	}
 
+	@FXML
+	public void showDonate() {
+		application.getHostServices().showDocument(DONATE_URI);
+	}
+
+	@FXML
+	public void showSponsors() {
+		application.getHostServices().showDocument(SPONSORS_URI);
+	}
+
+	@FXML
+	void didClickRemoveCert() {
+		removeCert.build().showRemoveCert(window);
+	}
+
 	public LicenseHolder getLicenseHolder() {
 		return licenseHolder;
 	}

+ 34 - 0
src/main/java/org/cryptomator/ui/removecert/RemoveCertComponent.java

@@ -0,0 +1,34 @@
+package org.cryptomator.ui.removecert;
+
+import dagger.Lazy;
+import dagger.Subcomponent;
+import org.cryptomator.ui.common.FxmlFile;
+import org.cryptomator.ui.common.FxmlScene;
+
+import javafx.scene.Scene;
+import javafx.stage.Stage;
+
+@RemoveCertScoped
+@Subcomponent(modules = {RemoveCertModule.class})
+public interface RemoveCertComponent {
+
+	@RemoveCertWindow
+	Stage window();
+
+	@FxmlScene(FxmlFile.REMOVE_CERT)
+	Lazy<Scene> scene();
+
+	default void showRemoveCert(Stage owner) {
+		Stage stage = window();
+		stage.setScene(scene().get());
+		stage.sizeToScene();
+		stage.initOwner(owner);
+		stage.show();
+	}
+
+	@Subcomponent.Builder
+	interface Builder {
+		RemoveCertComponent build();
+	}
+
+}

+ 32 - 0
src/main/java/org/cryptomator/ui/removecert/RemoveCertController.java

@@ -0,0 +1,32 @@
+package org.cryptomator.ui.removecert;
+
+import org.cryptomator.common.settings.Settings;
+import org.cryptomator.ui.common.FxController;
+
+import javax.inject.Inject;
+import javafx.fxml.FXML;
+import javafx.stage.Stage;
+
+@RemoveCertScoped
+public class RemoveCertController implements FxController {
+
+	private final Stage window;
+	private final Settings settings;
+
+	@Inject
+	public RemoveCertController(@RemoveCertWindow Stage window, Settings settings) {
+		this.window = window;
+		this.settings = settings;
+	}
+
+	@FXML
+	public void close() {
+		window.close();
+	}
+
+	@FXML
+	public void remove() {
+		settings.licenseKey.set(null);
+		window.close();
+	}
+}

+ 56 - 0
src/main/java/org/cryptomator/ui/removecert/RemoveCertModule.java

@@ -0,0 +1,56 @@
+package org.cryptomator.ui.removecert;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.Provides;
+import dagger.multibindings.IntoMap;
+import org.cryptomator.ui.common.DefaultSceneFactory;
+import org.cryptomator.ui.common.FxController;
+import org.cryptomator.ui.common.FxControllerKey;
+import org.cryptomator.ui.common.FxmlFile;
+import org.cryptomator.ui.common.FxmlLoaderFactory;
+import org.cryptomator.ui.common.FxmlScene;
+import org.cryptomator.ui.common.StageFactory;
+
+import javax.inject.Provider;
+import javafx.scene.Scene;
+import javafx.stage.Modality;
+import javafx.stage.Stage;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+@Module
+abstract class RemoveCertModule {
+
+	@Provides
+	@RemoveCertWindow
+	@RemoveCertScoped
+	static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
+		return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
+	}
+
+	@Provides
+	@RemoveCertWindow
+	@RemoveCertScoped
+	static Stage provideStage(StageFactory factory, ResourceBundle resourceBundle) {
+		Stage stage = factory.create();
+		stage.setTitle(resourceBundle.getString("removeCert.title"));
+		stage.setResizable(false);
+		stage.initModality(Modality.WINDOW_MODAL);
+		return stage;
+	}
+
+	@Provides
+	@FxmlScene(FxmlFile.REMOVE_CERT)
+	@RemoveCertScoped
+	static Scene provideRemoveCertScene(@RemoveCertWindow FxmlLoaderFactory fxmlLoaders) {
+		return fxmlLoaders.createScene(FxmlFile.REMOVE_CERT);
+	}
+
+	// ------------------
+
+	@Binds
+	@IntoMap
+	@FxControllerKey(RemoveCertController.class)
+	abstract FxController bindRemoveCertController(RemoveCertController controller);
+}

+ 13 - 0
src/main/java/org/cryptomator/ui/removecert/RemoveCertScoped.java

@@ -0,0 +1,13 @@
+package org.cryptomator.ui.removecert;
+
+import javax.inject.Scope;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Scope
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+public @interface RemoveCertScoped {
+
+}

+ 14 - 0
src/main/java/org/cryptomator/ui/removecert/RemoveCertWindow.java

@@ -0,0 +1,14 @@
+package org.cryptomator.ui.removecert;
+
+import javax.inject.Qualifier;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+@interface RemoveCertWindow {
+
+}

+ 1 - 0
src/main/resources/css/dark_theme.css

@@ -100,6 +100,7 @@
 
 .label-extra-large {
 	-fx-font-family: 'Open Sans SemiBold';
+	-fx-fill: TEXT_FILL;
 	-fx-font-size: 1.5em;
 }
 

+ 45 - 22
src/main/resources/fxml/preferences_contribute.fxml

@@ -3,13 +3,18 @@
 <?import org.cryptomator.ui.controls.FontAwesome5IconView?>
 <?import org.cryptomator.ui.controls.FormattedLabel?>
 <?import javafx.geometry.Insets?>
+<?import javafx.scene.control.Button?>
 <?import javafx.scene.control.Hyperlink?>
 <?import javafx.scene.control.Label?>
 <?import javafx.scene.control.TextArea?>
+<?import javafx.scene.image.Image?>
+<?import javafx.scene.image.ImageView?>
 <?import javafx.scene.layout.HBox?>
+<?import javafx.scene.layout.Region?>
 <?import javafx.scene.layout.StackPane?>
 <?import javafx.scene.layout.VBox?>
 <?import javafx.scene.shape.Circle?>
+<?import javafx.scene.text.Text?>
 <VBox xmlns:fx="http://javafx.com/fxml"
 	  xmlns="http://javafx.com/javafx"
 	  fx:controller="org.cryptomator.ui.preferences.SupporterCertificateController"
@@ -18,31 +23,49 @@
 		<Insets topRightBottomLeft="24"/>
 	</padding>
 	<children>
-		<StackPane VBox.vgrow="NEVER" prefHeight="60">
-			<HBox spacing="12" alignment="CENTER_LEFT" visible="${controller.licenseHolder.validLicense}">
-				<StackPane alignment="CENTER" HBox.hgrow="NEVER">
-					<Circle styleClass="glyph-icon-primary" radius="24"/>
-					<FontAwesome5IconView styleClass="glyph-icon-white" glyph="CROWN" glyphSize="24"/>
-				</StackPane>
+		<StackPane VBox.vgrow="NEVER" prefHeight="60" alignment="TOP_CENTER">
+			<VBox alignment="TOP_CENTER" visible="${controller.licenseHolder.validLicense}">
+				<Text styleClass="label-extra-large" text="%preferences.contribute.thankYou" wrappingWidth="400" textAlignment="CENTER"/>
+				<ImageView fitHeight="180">
+					<Image url="@../img/supporter_cert_stamp.png"/>
+				</ImageView>
 				<FormattedLabel format="%preferences.contribute.registeredFor" arg1="${controller.licenseHolder.licenseSubject}" wrapText="true"/>
-			</HBox>
-
-			<HBox spacing="12" alignment="CENTER_LEFT" visible="${!controller.licenseHolder.validLicense}">
-				<StackPane alignment="CENTER" HBox.hgrow="NEVER">
-					<Circle styleClass="glyph-icon-primary" radius="24"/>
-					<FontAwesome5IconView styleClass="glyph-icon-white" glyph="HAND_HOLDING_HEART" glyphSize="24"/>
-				</StackPane>
-				<VBox HBox.hgrow="ALWAYS" spacing="6">
-					<Label text="%preferences.contribute.noCertificate" wrapText="true" VBox.vgrow="ALWAYS"/>
-					<Hyperlink text="%preferences.contribute.getCertificate" onAction="#getSupporterCertificate" contentDisplay="LEFT">
+				<Region minHeight="12"/>
+				<HBox alignment="BOTTOM_CENTER" spacing="6">
+					<Button onAction="#didClickRemoveCert">
+						<graphic>
+							<FontAwesome5IconView glyph="TRASH"/>
+						</graphic>
+					</Button>
+					<Button text="%preferences.contribute.donate" minWidth="100" onAction="#showDonate">
 						<graphic>
-							<FontAwesome5IconView glyph="LINK"/>
+							<FontAwesome5IconView glyph="DONATE"/>
 						</graphic>
-					</Hyperlink>
-				</VBox>
-			</HBox>
+					</Button>
+					<Button text="%preferences.contribute.sponsor" minWidth="100" onAction="#showSponsors">
+						<graphic>
+							<FontAwesome5IconView glyph="SPONSORS"/>
+						</graphic>
+					</Button>
+				</HBox>
+			</VBox>
+			<VBox spacing="12" visible="${!controller.licenseHolder.validLicense}">
+				<HBox spacing="12" alignment="CENTER_LEFT">
+					<StackPane HBox.hgrow="NEVER">
+						<Circle styleClass="glyph-icon-primary" radius="24"/>
+						<FontAwesome5IconView styleClass="glyph-icon-white" glyph="HAND_HOLDING_HEART" glyphSize="24"/>
+					</StackPane>
+					<VBox HBox.hgrow="ALWAYS" spacing="6">
+						<Label text="%preferences.contribute.noCertificate" wrapText="true" VBox.vgrow="ALWAYS"/>
+						<Hyperlink text="%preferences.contribute.getCertificate" onAction="#getSupporterCertificate">
+							<graphic>
+								<FontAwesome5IconView glyph="LINK"/>
+							</graphic>
+						</Hyperlink>
+					</VBox>
+				</HBox>
+				<TextArea fx:id="supporterCertificateField" promptText="%preferences.contribute.promptText" wrapText="true" VBox.vgrow="ALWAYS" prefRowCount="6"/>
+			</VBox>
 		</StackPane>
-
-		<TextArea fx:id="supporterCertificateField" promptText="%preferences.contribute.promptText" wrapText="true" VBox.vgrow="ALWAYS" prefRowCount="6"/>
 	</children>
 </VBox>

+ 51 - 0
src/main/resources/fxml/remove_cert.fxml

@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
+<?import javafx.geometry.Insets?>
+<?import javafx.scene.control.Button?>
+<?import javafx.scene.control.ButtonBar?>
+<?import javafx.scene.control.Label?>
+<?import javafx.scene.layout.HBox?>
+<?import javafx.scene.layout.StackPane?>
+<?import javafx.scene.layout.VBox?>
+<?import javafx.scene.shape.Circle?>
+<?import javafx.scene.Group?>
+<?import javafx.scene.layout.Region?>
+<HBox xmlns:fx="http://javafx.com/fxml"
+	  xmlns="http://javafx.com/javafx"
+	  fx:controller="org.cryptomator.ui.removecert.RemoveCertController"
+	  minWidth="400"
+	  maxWidth="400"
+	  minHeight="145"
+	  spacing="12">
+	<padding>
+		<Insets topRightBottomLeft="12"/>
+	</padding>
+	<children>
+		<Group>
+			<StackPane>
+				<padding>
+					<Insets topRightBottomLeft="6"/>
+				</padding>
+				<Circle styleClass="glyph-icon-primary" radius="24"/>
+				<FontAwesome5IconView styleClass="glyph-icon-white" glyph="QUESTION" glyphSize="24"/>
+			</StackPane>
+		</Group>
+		<VBox HBox.hgrow="ALWAYS">
+			<Label styleClass="label-large" text="%removeCert.message" wrapText="true" >
+				<padding>
+					<Insets bottom="6" top="6"/>
+				</padding>
+			</Label>
+			<Label text="%removeCert.description" wrapText="true" />
+
+			<Region VBox.vgrow="ALWAYS" minHeight="18"/>
+			<ButtonBar buttonMinWidth="120" buttonOrder="+CI">
+				<buttons>
+					<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" defaultButton="true" cancelButton="true" onAction="#close"/>
+					<Button text="%removeCert.confirmBtn" ButtonBar.buttonData="FINISH" onAction="#remove"/>
+				</buttons>
+			</ButtonBar>
+		</VBox>
+	</children>
+</HBox>

+ 9 - 0
src/main/resources/i18n/strings.properties

@@ -336,6 +336,15 @@ preferences.contribute.registeredFor=Supporter certificate registered for %s
 preferences.contribute.noCertificate=Support Cryptomator and receive a supporter certificate. It's like a license key but for awesome people using free software. ;-)
 preferences.contribute.getCertificate=Don't have one already? Learn how you can obtain it.
 preferences.contribute.promptText=Paste supporter certificate code here
+preferences.contribute.thankYou=Thank you for supporting Cryptomator's open-source development!
+preferences.contribute.donate=Donate
+preferences.contribute.sponsor=Sponsor
+
+### Remove License Key Dialog
+removeCert.title=Remove Certificate
+removeCert.message=Remove supporter certificate?
+removeCert.description=Cryptomator's core features are not affected by this. Neither access to your vaults is restricted nor the level of security is lowered.
+removeCert.confirmBtn=Remove
 #<-- Add entries for donations and code/translation/documentation contribution -->
 
 ## About

BIN
src/main/resources/img/supporter_cert_stamp.png


BIN
src/main/resources/img/supporter_cert_stamp@2x.png