diff --git a/.github/workflows/mac-dmg.yml b/.github/workflows/mac-dmg.yml
index 3f3b45d9a..56ea3e94a 100644
--- a/.github/workflows/mac-dmg.yml
+++ b/.github/workflows/mac-dmg.yml
@@ -82,9 +82,10 @@ jobs:
--app-version "${{ steps.versions.outputs.semVerNum }}"
--java-options "-Xss5m"
--java-options "-Xmx256m"
- --java-options "-Dcryptomator.appVersion=\"${{ steps.versions.outputs.semVerStr }}\""
--java-options "-Dfile.encoding=\"utf-8\""
--java-options "-Dapple.awt.enableTemplateImages=true"
+ --java-options "-Dsun.java2d.metal=true"
+ --java-options "-Dcryptomator.appVersion=\"${{ steps.versions.outputs.semVerStr }}\""
--java-options "-Dcryptomator.logDir=\"~/Library/Logs/Cryptomator\""
--java-options "-Dcryptomator.pluginDir=\"~/Library/Application Support/Cryptomator/Plugins\""
--java-options "-Dcryptomator.settingsPath=\"~/Library/Application Support/Cryptomator/settings.json\""
@@ -103,6 +104,16 @@ jobs:
env:
VERSION_NO: ${{ steps.versions.outputs.semVerNum }}
REVISION_NO: ${{ steps.versions.outputs.revNum }}
+ - name: Generate license for dmg
+ run: >
+ mvn -B license:add-third-party
+ -Dlicense.thirdPartyFilename=license.rtf
+ -Dlicense.outputDirectory=dist/mac/dmg/resources
+ -Dlicense.fileTemplate=dist/mac/dmg/resources/licenseTemplate.ftl
+ -Dlicense.includedScopes=compile
+ -Dlicense.excludedGroups=^org\.cryptomator
+ -Dlicense.failOnMissing=true
+ -Dlicense.licenseMergesUrl=file://${{ github.workspace }}/license/merges
- name: Install codesign certificate
run: |
# create variables
diff --git a/.github/workflows/win-exe.yml b/.github/workflows/win-exe.yml
index 8a6e459b2..94e13c514 100644
--- a/.github/workflows/win-exe.yml
+++ b/.github/workflows/win-exe.yml
@@ -116,12 +116,17 @@ jobs:
timestampUrl: 'http://timestamp.digicert.com'
folder: appdir/Cryptomator
recursive: true
- - name: Generate license
+ - name: Generate license for MSI
run: >
mvn -B license:add-third-party
"-Dlicense.thirdPartyFilename=license.rtf"
- "-Dlicense.fileTemplate=dist/win/resources/licenseTemplate.ftl"
"-Dlicense.outputDirectory=dist/win/resources"
+ "-Dlicense.fileTemplate=dist/win/resources/licenseTemplate.ftl"
+ "-Dlicense.includedScopes=compile"
+ "-Dlicense.excludedGroups=^org\.cryptomator"
+ "-Dlicense.failOnMissing=true"
+ "-Dlicense.licenseMergesUrl=file:///${{ github.workspace }}/license/merges"
+ shell: pwsh
- name: Create MSI
run: >
${JAVA_HOME}/bin/jpackage
@@ -202,12 +207,17 @@ jobs:
distribution: 'temurin'
java-version: ${{ env.JAVA_VERSION }}
cache: 'maven'
- - name: Generate license
+ - name: Generate license for exe
run: >
mvn -B license:add-third-party
"-Dlicense.thirdPartyFilename=license.rtf"
"-Dlicense.fileTemplate=dist/win/bundle/resources/licenseTemplate.ftl"
"-Dlicense.outputDirectory=dist/win/bundle/resources"
+ "-Dlicense.includedScopes=compile"
+ "-Dlicense.excludedGroups=^org\.cryptomator"
+ "-Dlicense.failOnMissing=true"
+ "-Dlicense.licenseMergesUrl=file:///${{ github.workspace }}/license/merges"
+ shell: pwsh
- name: Download WinFsp
run:
curl --output dist/win/bundle/resources/winfsp.msi -L ${{ env.WINFSP_MSI }}
diff --git a/dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml b/dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml
index 58b95fb82..865ac739e 100644
--- a/dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml
+++ b/dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml
@@ -66,6 +66,7 @@
+
diff --git a/dist/mac/dmg/.gitignore b/dist/mac/dmg/.gitignore
index b8ef35283..cdc73d89b 100644
--- a/dist/mac/dmg/.gitignore
+++ b/dist/mac/dmg/.gitignore
@@ -2,4 +2,5 @@
Cryptomator.app/
runtime/
dmg/
-*.dmg
\ No newline at end of file
+*.dmg
+license.rtf
\ No newline at end of file
diff --git a/dist/mac/dmg/build.sh b/dist/mac/dmg/build.sh
index 2fd7c7b89..0d2db1219 100755
--- a/dist/mac/dmg/build.sh
+++ b/dist/mac/dmg/build.sh
@@ -56,12 +56,13 @@ ${JAVA_HOME}/bin/jpackage \
--name Cryptomator \
--vendor "Skymatic GmbH" \
--copyright "(C) 2016 - 2022 Skymatic GmbH" \
+ --app-version "${VERSION_NO}" \
--java-options "-Xss5m" \
--java-options "-Xmx256m" \
- --java-options "-Dcryptomator.appVersion=\"${VERSION_NO}\"" \
- --app-version "${VERSION_NO}" \
--java-options "-Dfile.encoding=\"utf-8\"" \
--java-options "-Dapple.awt.enableTemplateImages=true" \
+ --java-options "-Dsun.java2d.metal=true" \
+ --java-options "-Dcryptomator.appVersion=\"${VERSION_NO}\"" \
--java-options "-Dcryptomator.logDir=\"~/Library/Logs/Cryptomator\"" \
--java-options "-Dcryptomator.pluginDir=\"~/Library/Application Support/Cryptomator/Plugins\"" \
--java-options "-Dcryptomator.settingsPath=\"~/Library/Application Support/Cryptomator/settings.json\"" \
@@ -77,6 +78,16 @@ cp ../resources/Cryptomator-Vault.icns Cryptomator.app/Contents/Resources/
sed -i '' "s|###BUNDLE_SHORT_VERSION_STRING###|${VERSION_NO}|g" Cryptomator.app/Contents/Info.plist
sed -i '' "s|###BUNDLE_VERSION###|${REVISION_NO}|g" Cryptomator.app/Contents/Info.plist
+# generate license
+mvn -B -f../../../pom.xml license:add-third-party \
+ -Dlicense.thirdPartyFilename=license.rtf \
+ -Dlicense.outputDirectory=dist/mac/dmg/resources \
+ -Dlicense.fileTemplate=resources/licenseTemplate.ftl \
+ -Dlicense.includedScopes=compile \
+ -Dlicense.excludedGroups=^org\.cryptomator \
+ -Dlicense.failOnMissing=true \
+ -Dlicense.licenseMergesUrl=file://$(pwd)/../../../license/merges
+
# codesign
if [ -n "${CODESIGN_IDENTITY}" ]; then
find Cryptomator.app/Contents/runtime/Contents/MacOS -name '*.dylib' -exec codesign --force -s ${CODESIGN_IDENTITY} {} \;
diff --git a/dist/mac/dmg/resources/license.rtf b/dist/mac/dmg/resources/license.rtf
deleted file mode 100644
index 72730adb8..000000000
--- a/dist/mac/dmg/resources/license.rtf
+++ /dev/null
@@ -1,100 +0,0 @@
-{\rtf1\ansi\ansicpg1252\cocoartf2512
-\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica-Bold;\f1\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\paperw11900\paperh16840\vieww12000\viewh15840\viewkind0
-\deftab720
-\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardeftab720\partightenfactor0
-
-\f0\b\fs24 \cf0 Cryptomator is distributed under the GPLv3 License, found below. Please see the bottom of this document for any other license applicable to code used within Cryptomator.
-\f1\b0 \
-\
-
-\f0\b \'a9 2016 \'96 2022 Skymatic GmbH
-\f1\b0 \
-\
-This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\
-\
-This program 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 General Public License for more details.\
-\
-You should have received a copy of the GNU General Public License along with this program. If not, see {\field{\*\fldinst{HYPERLINK "http://www.gnu.org/licenses/"}}{\fldrslt http://www.gnu.org/licenses/}}.\
-\
-
-\f0\b Cryptomator uses 49 third-party dependencies under the following licenses:
-\f1\b0 \
- Apache License v2.0:\
- - jffi (com.github.jnr:jffi:1.2.23 - {\field{\*\fldinst{HYPERLINK "http://github.com/jnr/jffi"}}{\fldrslt http://github.com/jnr/jffi}})\
- - jnr-a64asm (com.github.jnr:jnr-a64asm:1.0.0 - {\field{\*\fldinst{HYPERLINK "http://nexus.sonatype.org/oss-repository-hosting.html/jnr-a64asm"}}{\fldrslt http://nexus.sonatype.org/oss-repository-hosting.html/jnr-a64asm}})\
- - jnr-constants (com.github.jnr:jnr-constants:0.9.15 - {\field{\*\fldinst{HYPERLINK "http://github.com/jnr/jnr-constants"}}{\fldrslt http://github.com/jnr/jnr-constants}})\
- - jnr-ffi (com.github.jnr:jnr-ffi:2.1.12 - {\field{\*\fldinst{HYPERLINK "http://github.com/jnr/jnr-ffi"}}{\fldrslt http://github.com/jnr/jnr-ffi}})\
- - FindBugs-jsr305 (com.google.code.findbugs:jsr305:3.0.2 - {\field{\*\fldinst{HYPERLINK "http://findbugs.sourceforge.net/"}}{\fldrslt http://findbugs.sourceforge.net/}})\
- - Gson (com.google.code.gson:gson:2.8.6 - {\field{\*\fldinst{HYPERLINK "https://github.com/google/gson/gson"}}{\fldrslt https://github.com/google/gson/gson}})\
- - Dagger (com.google.dagger:dagger:2.29.1 - {\field{\*\fldinst{HYPERLINK "https://github.com/google/dagger"}}{\fldrslt https://github.com/google/dagger}})\
- - error-prone annotations (com.google.errorprone:error_prone_annotations:2.3.4 - {\field{\*\fldinst{HYPERLINK "http://nexus.sonatype.org/oss-repository-hosting.html/error_prone_parent/error_prone_annotation"}}{\fldrslt http://nexus.sonatype.org/oss-repository-hosting.html/error_prone_parent/error_prone_annotation}} )\
- - Guava InternalFutureFailureAccess and InternalFutures (com.google.guava:failureaccess:1.0.1 - {\field{\*\fldinst{HYPERLINK "https://github.com/google/guava/failureaccess"}}{\fldrslt https://github.com/google/guava/failureaccess}})\
- - Guava: Google Core Libraries for Java (com.google.guava:guava:30.0-jre - {\field{\*\fldinst{HYPERLINK "https://github.com/google/guava/guava"}}{\fldrslt https://github.com/google/guava/guava}})\
- - Guava ListenableFuture only (com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava - {\field{\*\fldinst{HYPERLINK "https://github.com/google/guava/listenablefuture"}}{\fldrslt https://github.com/google/guava/listenablefuture}})\
- - J2ObjC Annotations (com.google.j2objc:j2objc-annotations:1.3 - {\field{\*\fldinst{HYPERLINK "https://github.com/google/j2objc/"}}{\fldrslt https://github.com/google/j2objc/}})\
- - Apache Commons CLI (commons-cli:commons-cli:1.4 - {\field{\*\fldinst{HYPERLINK "http://commons.apache.org/proper/commons-cli/"}}{\fldrslt http://commons.apache.org/proper/commons-cli/}})\
- - javax.inject (javax.inject:javax.inject:1 - {\field{\*\fldinst{HYPERLINK "http://code.google.com/p/atinject/"}}{\fldrslt http://code.google.com/p/atinject/}})\
- - Java Native Access (net.java.dev.jna:jna:5.6.0 - {\field{\*\fldinst{HYPERLINK "https://github.com/java-native-access/jna"}}{\fldrslt https://github.com/java-native-access/jna}})\
- - Java Native Access Platform (net.java.dev.jna:jna-platform:5.5.0 - {\field{\*\fldinst{HYPERLINK "https://github.com/java-native-access/jna"}}{\fldrslt https://github.com/java-native-access/jna}})\
- - Apache Commons Lang (org.apache.commons:commons-lang3:3.11 - {\field{\*\fldinst{HYPERLINK "https://commons.apache.org/proper/commons-lang/"}}{\fldrslt https://commons.apache.org/proper/commons-lang/}})\
- - Apache HttpCore (org.apache.httpcomponents:httpcore:4.4.13 - {\field{\*\fldinst{HYPERLINK "http://hc.apache.org/httpcomponents-core-ga"}}{\fldrslt http://hc.apache.org/httpcomponents-core-ga}})\
- - Jackrabbit WebDAV Library (org.apache.jackrabbit:jackrabbit-webdav:2.21.3 - {\field{\*\fldinst{HYPERLINK "http://jackrabbit.apache.org/jackrabbit-webdav/"}}{\fldrslt http://jackrabbit.apache.org/jackrabbit-webdav/}})\
- - Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.35.v20201120 - {\field{\*\fldinst{HYPERLINK "https://eclipse.org/jetty/jetty-http"}}{\fldrslt https://eclipse.org/jetty/jetty-http}})\
- - Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.35.v20201120 - {\field{\*\fldinst{HYPERLINK "https://eclipse.org/jetty/jetty-io"}}{\fldrslt https://eclipse.org/jetty/jetty-io}})\
- - Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.35.v20201120 - {\field{\*\fldinst{HYPERLINK "https://eclipse.org/jetty/jetty-security"}}{\fldrslt https://eclipse.org/jetty/jetty-security}})\
- - Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.35.v20201120 - {\field{\*\fldinst{HYPERLINK "https://eclipse.org/jetty/jetty-server"}}{\fldrslt https://eclipse.org/jetty/jetty-server}})\
- - Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.35.v20201120 - {\field{\*\fldinst{HYPERLINK "https://eclipse.org/jetty/jetty-servlet"}}{\fldrslt https://eclipse.org/jetty/jetty-servlet}})\
- - Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.35.v20201120 - {\field{\*\fldinst{HYPERLINK "https://eclipse.org/jetty/jetty-util"}}{\fldrslt https://eclipse.org/jetty/jetty-util}})\
- - Jetty :: Utilities :: Ajax(JSON) (org.eclipse.jetty:jetty-util-ajax:9.4.35.v20201120 - {\field{\*\fldinst{HYPERLINK "https://eclipse.org/jetty/jetty-util-ajax"}}{\fldrslt https://eclipse.org/jetty/jetty-util-ajax}})\
- - Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.35.v20201120 - {\field{\*\fldinst{HYPERLINK "https://eclipse.org/jetty/jetty-webapp"}}{\fldrslt https://eclipse.org/jetty/jetty-webapp}})\
- - Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.35.v20201120 - {\field{\*\fldinst{HYPERLINK "https://eclipse.org/jetty/jetty-xml"}}{\fldrslt https://eclipse.org/jetty/jetty-xml}})\
- BSD:\
- - asm (org.ow2.asm:asm:7.1 - {\field{\*\fldinst{HYPERLINK "http://asm.ow2.org/"}}{\fldrslt http://asm.ow2.org/}})\
- - asm-analysis (org.ow2.asm:asm-analysis:7.1 - {\field{\*\fldinst{HYPERLINK "http://asm.ow2.org/"}}{\fldrslt http://asm.ow2.org/}})\
- - asm-commons (org.ow2.asm:asm-commons:7.1 - {\field{\*\fldinst{HYPERLINK "http://asm.ow2.org/"}}{\fldrslt http://asm.ow2.org/}})\
- - asm-tree (org.ow2.asm:asm-tree:7.1 - {\field{\*\fldinst{HYPERLINK "http://asm.ow2.org/"}}{\fldrslt http://asm.ow2.org/}})\
- - asm-util (org.ow2.asm:asm-util:7.1 - {\field{\*\fldinst{HYPERLINK "http://asm.ow2.org/"}}{\fldrslt http://asm.ow2.org/}})\
- Eclipse Public License - Version 1.0:\
- - Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.35.v20201120 - {\field{\*\fldinst{HYPERLINK "https://eclipse.org/jetty/jetty-http"}}{\fldrslt https://eclipse.org/jetty/jetty-http}})\
- - Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.35.v20201120 - {\field{\*\fldinst{HYPERLINK "https://eclipse.org/jetty/jetty-io"}}{\fldrslt https://eclipse.org/jetty/jetty-io}})\
- - Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.35.v20201120 - {\field{\*\fldinst{HYPERLINK "https://eclipse.org/jetty/jetty-security"}}{\fldrslt https://eclipse.org/jetty/jetty-security}})\
- - Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.35.v20201120 - {\field{\*\fldinst{HYPERLINK "https://eclipse.org/jetty/jetty-server"}}{\fldrslt https://eclipse.org/jetty/jetty-server}})\
- - Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.35.v20201120 - {\field{\*\fldinst{HYPERLINK "https://eclipse.org/jetty/jetty-servlet"}}{\fldrslt https://eclipse.org/jetty/jetty-servlet}})\
- - Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.35.v20201120 - {\field{\*\fldinst{HYPERLINK "https://eclipse.org/jetty/jetty-util"}}{\fldrslt https://eclipse.org/jetty/jetty-util}})\
- - Jetty :: Utilities :: Ajax(JSON) (org.eclipse.jetty:jetty-util-ajax:9.4.35.v20201120 - {\field{\*\fldinst{HYPERLINK "https://eclipse.org/jetty/jetty-util-ajax"}}{\fldrslt https://eclipse.org/jetty/jetty-util-ajax}})\
- - Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.35.v20201120 - {\field{\*\fldinst{HYPERLINK "https://eclipse.org/jetty/jetty-webapp"}}{\fldrslt https://eclipse.org/jetty/jetty-webapp}})\
- - Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.35.v20201120 - {\field{\*\fldinst{HYPERLINK "https://eclipse.org/jetty/jetty-xml"}}{\fldrslt https://eclipse.org/jetty/jetty-xml}})\
- Eclipse Public License - v 2.0:\
- - jnr-posix (com.github.jnr:jnr-posix:3.0.54 - {\field{\*\fldinst{HYPERLINK "http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix"}}{\fldrslt http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix}})\
- GPLv2:\
- - jnr-posix (com.github.jnr:jnr-posix:3.0.54 - {\field{\*\fldinst{HYPERLINK "http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix"}}{\fldrslt http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix}})\
- GPLv2+CE:\
- - Java Servlet API (javax.servlet:javax.servlet-api:3.1.0 - {\field{\*\fldinst{HYPERLINK "http://servlet-spec.java.net"}}{\fldrslt http://servlet-spec.java.net}})\
- - javafx-base (org.openjfx:javafx-base:15 - {\field{\*\fldinst{HYPERLINK "https://openjdk.java.net/projects/openjfx/javafx-base/"}}{\fldrslt https://openjdk.java.net/projects/openjfx/javafx-base/}})\
- - javafx-controls (org.openjfx:javafx-controls:15 - {\field{\*\fldinst{HYPERLINK "https://openjdk.java.net/projects/openjfx/javafx-controls/"}}{\fldrslt https://openjdk.java.net/projects/openjfx/javafx-controls/}})\
- - javafx-fxml (org.openjfx:javafx-fxml:15 - {\field{\*\fldinst{HYPERLINK "https://openjdk.java.net/projects/openjfx/javafx-fxml/"}}{\fldrslt https://openjdk.java.net/projects/openjfx/javafx-fxml/}})\
- - javafx-graphics (org.openjfx:javafx-graphics:15 - {\field{\*\fldinst{HYPERLINK "https://openjdk.java.net/projects/openjfx/javafx-graphics/"}}{\fldrslt https://openjdk.java.net/projects/openjfx/javafx-graphics/}})\
- LGPL 2.1:\
- - jnr-posix (com.github.jnr:jnr-posix:3.0.54 - {\field{\*\fldinst{HYPERLINK "http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix"}}{\fldrslt http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix}})\
- - Java Native Access (net.java.dev.jna:jna:5.6.0 - https://github.com/java-native-access/jna)\
- - Java Native Access Platform (net.java.dev.jna:jna-platform:5.5.0 - {\field{\*\fldinst{HYPERLINK "https://github.com/java-native-access/jna"}}{\fldrslt https://github.com/java-native-access/jna}})\
- MIT License:\
- - java jwt (com.auth0:java-jwt:3.12.0 - {\field{\*\fldinst{HYPERLINK "https://github.com/auth0/java-jwt"}}{\fldrslt https://github.com/auth0/java-jwt}})\
- - jnr-x86asm (com.github.jnr:jnr-x86asm:1.0.2 - {\field{\*\fldinst{HYPERLINK "http://github.com/jnr/jnr-x86asm"}}{\fldrslt http://github.com/jnr/jnr-x86asm}})\
- - jnr-fuse (com.github.serceman:jnr-fuse:0.5.4 - no url defined)\
- - zxcvbn4j (com.nulab-inc:zxcvbn:1.3.0 - {\field{\*\fldinst{HYPERLINK "https://github.com/nulab/zxcvbn4j"}}{\fldrslt https://github.com/nulab/zxcvbn4j}})\
- - Checker Qual (org.checkerframework:checker-qual:3.5.0 - {\field{\*\fldinst{HYPERLINK "https://checkerframework.org"}}{\fldrslt https://checkerframework.org}})\
- - SLF4J API Module (org.slf4j:slf4j-api:1.7.30 - {\field{\*\fldinst{HYPERLINK "http://www.slf4j.org"}}{\fldrslt http://www.slf4j.org}})\
- The BSD 2-Clause License:\
- - EasyBind (com.tobiasdiez:easybind:2.1.0 - {\field{\*\fldinst{HYPERLINK "https://github.com/tobiasdiez/EasyBind"}}{\fldrslt https://github.com/tobiasdiez/EasyBind}})\
-\
-
-\f0\b Cryptomator uses other third-party assets under the following licenses:
-\f1\b0 \
- SIL OFL 1.1 License:\
- - Font Awesome 5.12.0 ({\field{\*\fldinst{HYPERLINK "https://fontawesome.com/"}}{\fldrslt https://fontawesome.com/}})\
-\
-}
diff --git a/dist/mac/dmg/resources/licenseTemplate.ftl b/dist/mac/dmg/resources/licenseTemplate.ftl
new file mode 100644
index 000000000..e4d7fd476
--- /dev/null
+++ b/dist/mac/dmg/resources/licenseTemplate.ftl
@@ -0,0 +1,49 @@
+<#function artifactFormat p>
+ <#if p.name?index_of('Unnamed') > -1>
+ <#return "{\\field{\\*\\fldinst{HYPERLINK \"" + (p.url!"no url defined") + "\"}}{\\fldrslt " + p.artifactId + "}}" + " (" + p.groupId + ":" + p.artifactId + ":" + p.version + ")">
+ <#else>
+ <#return "{\\field{\\*\\fldinst{HYPERLINK \"" + (p.url!"no url defined") + "\"}}{\\fldrslt " + p.name + "}}" + " (" + p.groupId + ":" + p.artifactId + ":" + p.version + ")">
+ #if>
+#function>
+{\rtf1\ansi\ansicpg1252\cocoartf2512
+\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica-Bold;\f1\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+{\*\expandedcolortbl;;}
+\paperw11900\paperh16840\vieww12000\viewh15840\viewkind0
+\deftab720
+\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardeftab720\partightenfactor0
+
+\f0\b\fs24 \cf0 Cryptomator is distributed under the GPLv3 License, found below. Please see the bottom of this document for any other license applicable to code used within Cryptomator.
+\f1\b0 \
+\
+
+\f0\b \'a9 2016 \'96 2022 Skymatic GmbH
+\f1\b0 \
+\
+This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\
+\
+This program 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 General Public License for more details.\
+\
+You should have received a copy of the GNU General Public License along with this program. If not, see {\field{\*\fldinst{HYPERLINK "http://www.gnu.org/licenses/"}}{\fldrslt http://www.gnu.org/licenses/}}.\
+\
+
+\f0\b Cryptomator uses ${dependencyMap?size} third-party dependencies under the following licenses:
+\f1\b0 \
+<#list licenseMap as e>
+<#assign license = e.getKey()/>
+<#assign projects = e.getValue()/>
+<#if projects?size > 0>
+ ${license}:\
+<#list projects as project>
+ - ${artifactFormat(project)}\
+#list>
+#if>
+#list>
+\
+
+\f0\b Cryptomator uses other third-party assets under the following licenses:
+\f1\b0 \
+ SIL OFL 1.1 License:\
+ - {\field{\*\fldinst{HYPERLINK "https://fontawesome.com/"}}{\fldrslt Font Awesome}} (5.12.0)\
+\
+}
diff --git a/dist/win/build.ps1 b/dist/win/build.ps1
index 883bd8f53..e491769e1 100644
--- a/dist/win/build.ps1
+++ b/dist/win/build.ps1
@@ -86,7 +86,11 @@ if ($clean -and (Test-Path -Path $appPath)) {
&mvn -B -f $buildDir/../../pom.xml license:add-third-party `
"-Dlicense.thirdPartyFilename=license.rtf" `
"-Dlicense.fileTemplate=$buildDir\resources\licenseTemplate.ftl" `
- "-Dlicense.outputDirectory=$buildDir\resources\"
+ "-Dlicense.outputDirectory=$buildDir\resources\" `
+ "-Dlicense.includedScopes=compile" `
+ "-Dlicense.excludedGroups=^org\.cryptomator" `
+ "-Dlicense.failOnMissing=true" `
+ "-Dlicense.licenseMergesUrl=file:///$buildDir/../../license/merges"
# patch app dir
Copy-Item "contrib\*" -Destination "Cryptomator"
@@ -122,7 +126,11 @@ $Env:JP_WIXWIZARD_RESOURCES = "$buildDir\resources"
&mvn -B -f $buildDir/../../pom.xml license:add-third-party `
"-Dlicense.thirdPartyFilename=license.rtf" `
"-Dlicense.fileTemplate=$buildDir\bundle\resources\licenseTemplate.ftl" `
- "-Dlicense.outputDirectory=$buildDir\bundle\resources\"
+ "-Dlicense.outputDirectory=$buildDir\bundle\resources\" `
+ "-Dlicense.includedScopes=compile" `
+ "-Dlicense.excludedGroups=^org\.cryptomator" `
+ "-Dlicense.failOnMissing=true" `
+ "-Dlicense.licenseMergesUrl=file:///$buildDir/../../license/merges"
# download Winfsp
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
diff --git a/dist/win/bundle/resources/licenseTemplate.ftl b/dist/win/bundle/resources/licenseTemplate.ftl
index bd137a1a1..8a568b85d 100644
--- a/dist/win/bundle/resources/licenseTemplate.ftl
+++ b/dist/win/bundle/resources/licenseTemplate.ftl
@@ -5,18 +5,18 @@
<#return p.name + " (" + p.groupId + ":" + p.artifactId + ":" + p.version + " - {{\\field{\\*\\fldinst{HYPERLINK " + (p.url!"no url defined") + "}}{\\fldrslt{" + (p.url!"no url defined") + "\\ul0\\cf0}}}}\\f0\\fs16 ) ">
#if>
#function>
-{\rtf1\ansi\ansicpg1252\deff0\nouicompat{\fonttbl{\f0\fnil\fcharset0 Arial;}}
+{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1031{\fonttbl{\f0\fnil\fcharset0 Segoe UI;}}
{\colortbl ;\red0\green0\blue255;}
-\viewkind4\uc1
-\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\b\fs16\lang7 Cryptomator is distributed under the GPLv3 License, found below. Please see the bottom of this document for any other license applicable to code used within Cryptomator.\b0\par
+\vieww12000\viewh15840\viewkind0
+\pard\tx283\tx567\tx850\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\b\fs16\lang7 Cryptomator is distributed under the GPLv3 License, found below. Please see the bottom of this document for any other license applicable to code used within Cryptomator.\b0\par
\par
-\b\'a9 2016 \endash 2022 Skymatic GmbH\b0\par
+\b\'a9 2016 \'96 2022 Skymatic GmbH \b0\par
\par
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\par
\par
This program 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 General Public License for more details.\par
\par
-You should have received a copy of the GNU General Public License along with this program. If not, see {{\field{\*\fldinst{HYPERLINK http://www.gnu.org/licenses/ }}{\fldrslt{http://www.gnu.org/licenses/\ul0\cf0}}}}\f0\fs16 .\par
+You should have received a copy of the GNU General Public License along with this program. If not, see {{\field{\*\fldinst{HYPERLINK http://www.gnu.org/licenses/ }}{\fldrslt{http://www.gnu.org/licenses/\ul0\cf0}}}}\f0\fs16 .\par
\par
\b Cryptomator uses ${dependencyMap?size} third-party dependencies under the following licenses:\b0\par
@@ -26,7 +26,7 @@ You should have received a copy of the GNU General Public License along with thi
<#if projects?size > 0>
\tab ${license}:\par
<#list projects as project>
-\tab\tab- ${artifactFormat(project)}\par
+\tab\tab - ${artifactFormat(project)}\par
#list>
#if>
#list>
@@ -38,4 +38,4 @@ You should have received a copy of the GNU General Public License along with thi
\b Cryptomator dynamically links to third-party libraries under the following license:\b0\par
\tab Uncategorized License:\par
\tab\tab - WinFsp - Windows File System Proxy, Copyright (C) Bill Zissimopoulos ({{\field{\*\fldinst{HYPERLINK https://github.com/billziss-gh/winfsp }}{\fldrslt{https://github.com/billziss-gh/winfsp\ul0\cf0}}}}\f0\fs16 )\b\par
-}
\ No newline at end of file
+}
diff --git a/dist/win/resources/licenseTemplate.ftl b/dist/win/resources/licenseTemplate.ftl
index d442e6538..0ee793cb1 100644
--- a/dist/win/resources/licenseTemplate.ftl
+++ b/dist/win/resources/licenseTemplate.ftl
@@ -5,18 +5,18 @@
<#return p.name + " (" + p.groupId + ":" + p.artifactId + ":" + p.version + " - {{\\field{\\*\\fldinst{HYPERLINK " + (p.url!"no url defined") + "}}{\\fldrslt{" + (p.url!"no url defined") + "\\ul0\\cf0}}}}\\f0\\fs16 ) ">
#if>
#function>
-{\rtf1\ansi\ansicpg1252\deff0\nouicompat{\fonttbl{\f0\fnil\fcharset0 Arial;}}
+{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1031{\fonttbl{\f0\fnil\fcharset0 Segoe UI;}}
{\colortbl ;\red0\green0\blue255;}
-\viewkind4\uc1
-\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\b\fs16\lang7 Cryptomator is distributed under the GPLv3 License, found below. Please see the bottom of this document for any other license applicable to code used within Cryptomator.\b0\par
+\vieww12000\viewh15840\viewkind0
+\pard\tx283\tx567\tx850\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\b\fs16\lang7 Cryptomator is distributed under the GPLv3 License, found below. Please see the bottom of this document for any other license applicable to code used within Cryptomator.\b0\par
\par
-\b\'a9 2016 \endash 2022 Skymatic GmbH\b0\par
+\b\'a9 2016 \'96 2022 Skymatic GmbH \b0\par
\par
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\par
\par
This program 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 General Public License for more details.\par
\par
-You should have received a copy of the GNU General Public License along with this program. If not, see {{\field{\*\fldinst{HYPERLINK http://www.gnu.org/licenses/ }}{\fldrslt{http://www.gnu.org/licenses/\ul0\cf0}}}}\f0\fs16 .\par
+You should have received a copy of the GNU General Public License along with this program. If not, see {{\field{\*\fldinst{HYPERLINK http://www.gnu.org/licenses/ }}{\fldrslt{http://www.gnu.org/licenses/\ul0\cf0}}}}\f0\fs16 .\par
\par
\b Cryptomator uses ${dependencyMap?size} third-party dependencies under the following licenses:\b0\par
@@ -26,12 +26,12 @@ You should have received a copy of the GNU General Public License along with thi
<#if projects?size > 0>
\tab ${license}:\par
<#list projects as project>
-\tab\tab- ${artifactFormat(project)}\par
+\tab\tab - ${artifactFormat(project)}\par
#list>
#if>
#list>
\par
\b Cryptomator uses other third-party assets under the following licenses:\b0\par
\tab SIL OFL 1.1 License:\par
-\tab\tab - Font Awesome 5.12.0 ({{\field{\*\fldinst{HYPERLINK https://fontawesome.com/ }}{\fldrslt{https://fontawesome.com/\ul0\cf0}}}}\f0\fs16 )\b\par
+\tab\tab - Font Awesome (5.12.0 - {{\field{\*\fldinst{HYPERLINK https://fontawesome.com/ }}{\fldrslt{https://fontawesome.com/\ul0\cf0}}}}\f0\fs16 )\b\par
}
\ No newline at end of file
diff --git a/license/merges b/license/merges
new file mode 100644
index 000000000..eb3a32a5b
--- /dev/null
+++ b/license/merges
@@ -0,0 +1,7 @@
+Apache License v2.0|Apache License, Version 2.0|The Apache Software License, Version 2.0|Apache 2.0|Apache Software License - Version 2.0|Apache-2.0
+MIT License|The MIT License (MIT)|The MIT License|MIT license
+LGPL 2.1|LGPL, version 2.1|GNU Lesser/Library General Public License version 2|GNU Lesser General Public License Version 2.1
+GPLv2|GNU General Public License Version 2
+GPLv2+CE|CDDL + GPLv2 with classpath exception
+Eclipse Public License - Version 1.0|Eclipse Public License - v 1.0
+Eclipse Public License - Version 2.0|Eclipse Public License - v 2.0
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 518d17251..ce0324ada 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,24 +28,24 @@
2.1.0-beta3
- 2.4.0
- 1.1.0-beta1
- 1.0.0
- 1.0.0
- 1.0.1
+ 2.4.1
+ 1.1.0
+ 1.1.0
+ 1.1.0
+ 1.1.0
1.3.3
1.3.3
1.2.7
- 18
+ 18.0.1
3.12.0
3.19.1
2.2
31.1-jre
2.41
2.9.0
- 1.6.0
+ 1.7.0
1.7.36
1.2.11
@@ -56,7 +56,7 @@
23.0.0
- 7.0.2
+ 7.1.0
0.8.7
@@ -314,6 +314,41 @@
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 3.0.0
+
+
+ compile-light-theme
+ compile
+
+ java
+
+
+ javafx.graphics/com.sun.javafx.css.parser.Css2Bin
+
+ ${project.basedir}/src/main/resources/css/light_theme.css
+ ${project.build.outputDirectory}/css/light_theme.bss
+
+
+
+
+ compile-dark-theme
+ compile
+
+ java
+
+
+ javafx.graphics/com.sun.javafx.css.parser.Css2Bin
+
+ ${project.basedir}/src/main/resources/css/dark_theme.css
+ ${project.build.outputDirectory}/css/dark_theme.bss
+
+
+
+
+
org.apache.maven.plugins
maven-jar-plugin
@@ -371,23 +406,24 @@
generate-resources
- ${project.basedir}/src/main/resources/license
THIRD-PARTY.txt
compile
org\.cryptomator
-
- Apache License v2.0|Apache License, Version 2.0|The Apache Software License, Version 2.0|Apache 2.0|Apache Software License - Version 2.0
- MIT License|The MIT License (MIT)|The MIT License|MIT license
- LGPL 2.1|LGPL, version 2.1|GNU Lesser/Library General Public License version 2|GNU Lesser General Public License Version 2.1
- GPLv2|GNU General Public License Version 2
- GPLv2+CE|CDDL + GPLv2 with classpath exception
-
- ${project.basedir}/src/license/template.ftl
+ file:///${project.basedir}/license/merges
+ ${project.basedir}/src/main/resources/license/template.ftl
+
+
+ src/main/resources
+
+ license/*
+
+
+
diff --git a/src/license/THIRD-PARTY.properties b/src/license/THIRD-PARTY.properties
deleted file mode 100644
index 7af1b122f..000000000
--- a/src/license/THIRD-PARTY.properties
+++ /dev/null
@@ -1 +0,0 @@
-com.github.serceman--jnr-fuse--0.5.4=MIT License
\ No newline at end of file
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index 7138bcf09..de9647138 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -1,7 +1,5 @@
-import org.cryptomator.integrations.autostart.AutoStartProvider;
-import org.cryptomator.integrations.keychain.KeychainAccessProvider;
-import org.cryptomator.integrations.tray.TrayIntegrationProvider;
-import org.cryptomator.integrations.uiappearance.UiAppearanceProvider;
+import org.cryptomator.integrations.tray.TrayMenuController;
+import org.cryptomator.ui.traymenu.AwtTrayMenuController;
module org.cryptomator.desktop {
requires static org.jetbrains.annotations;
@@ -38,10 +36,8 @@ module org.cryptomator.desktop {
requires logback.core;
requires com.nimbusds.jose.jwt;
- uses AutoStartProvider;
- uses KeychainAccessProvider;
- uses TrayIntegrationProvider;
- uses UiAppearanceProvider;
+ exports org.cryptomator.ui.traymenu to org.cryptomator.integrations.api;
+ provides TrayMenuController with AwtTrayMenuController;
exports org.cryptomator.ui.keyloading.hub to com.fasterxml.jackson.databind;
diff --git a/src/main/java/org/cryptomator/common/Environment.java b/src/main/java/org/cryptomator/common/Environment.java
index d1c18aa1e..10886df61 100644
--- a/src/main/java/org/cryptomator/common/Environment.java
+++ b/src/main/java/org/cryptomator/common/Environment.java
@@ -43,7 +43,6 @@ public class Environment {
LOG.debug("cryptomator.appVersion: {}", System.getProperty("cryptomator.appVersion"));
LOG.debug("cryptomator.buildNumber: {}", System.getProperty("cryptomator.buildNumber"));
LOG.debug("cryptomator.showTrayIcon: {}", System.getProperty("cryptomator.showTrayIcon"));
- LOG.debug("fuse.experimental: {}", Boolean.getBoolean("fuse.experimental"));
}
public boolean useCustomLogbackConfig() {
diff --git a/src/main/java/org/cryptomator/common/PluginClassLoader.java b/src/main/java/org/cryptomator/common/PluginClassLoader.java
deleted file mode 100644
index 16932923b..000000000
--- a/src/main/java/org/cryptomator/common/PluginClassLoader.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.cryptomator.common;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.nio.file.FileVisitOption;
-import java.nio.file.FileVisitResult;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.SimpleFileVisitor;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.List;
-
-@Singleton
-public class PluginClassLoader extends URLClassLoader {
-
- private static final Logger LOG = LoggerFactory.getLogger(PluginClassLoader.class);
- private static final String NAME = "PluginClassLoader";
- private static final String JAR_SUFFIX = ".jar";
-
- @Inject
- public PluginClassLoader(Environment env) {
- super(NAME, env.getPluginDir().map(PluginClassLoader::findJars).orElse(new URL[0]), PluginClassLoader.class.getClassLoader());
- }
-
- private static URL[] findJars(Path path) {
- if (!Files.isDirectory(path)) {
- return new URL[0];
- } else {
- try {
- var visitor = new JarVisitor();
- Files.walkFileTree(path, EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, visitor);
- return visitor.urls.toArray(URL[]::new);
- } catch (IOException e) {
- LOG.warn("Failed to scan plugin dir " + path, e);
- return new URL[0];
- }
- }
- }
-
- private static final class JarVisitor extends SimpleFileVisitor {
-
- private final List urls = new ArrayList<>();
-
- @Override
- public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
- if (attrs.isRegularFile() && file.getFileName().toString().toLowerCase().endsWith(JAR_SUFFIX)) {
- try {
- urls.add(file.toUri().toURL());
- } catch (MalformedURLException e) {
- LOG.warn("Failed to create URL for jar file {}", file);
- }
- }
- return FileVisitResult.CONTINUE;
- }
- }
-
-}
diff --git a/src/main/java/org/cryptomator/common/keychain/KeychainManager.java b/src/main/java/org/cryptomator/common/keychain/KeychainManager.java
index d6adadfe4..48b0a0ed5 100644
--- a/src/main/java/org/cryptomator/common/keychain/KeychainManager.java
+++ b/src/main/java/org/cryptomator/common/keychain/KeychainManager.java
@@ -43,12 +43,6 @@ public class KeychainManager implements KeychainAccessProvider {
return getClass().getName();
}
- @Override
- public void storePassphrase(String key, CharSequence passphrase) throws KeychainAccessException {
- getKeychainOrFail().storePassphrase(key, passphrase);
- setPassphraseStored(key, true);
- }
-
@Override
public void storePassphrase(String key, String displayName, CharSequence passphrase) throws KeychainAccessException {
getKeychainOrFail().storePassphrase(key, displayName, passphrase);
@@ -68,14 +62,6 @@ public class KeychainManager implements KeychainAccessProvider {
setPassphraseStored(key, false);
}
- @Override
- public void changePassphrase(String key, CharSequence passphrase) throws KeychainAccessException {
- if (isPassphraseStored(key)) {
- getKeychainOrFail().changePassphrase(key, passphrase);
- setPassphraseStored(key, true);
- }
- }
-
@Override
public void changePassphrase(String key, String displayName, CharSequence passphrase) throws KeychainAccessException {
if (isPassphraseStored(key)) {
diff --git a/src/main/java/org/cryptomator/common/keychain/KeychainModule.java b/src/main/java/org/cryptomator/common/keychain/KeychainModule.java
index 6356c4966..63749b445 100644
--- a/src/main/java/org/cryptomator/common/keychain/KeychainModule.java
+++ b/src/main/java/org/cryptomator/common/keychain/KeychainModule.java
@@ -2,42 +2,30 @@ package org.cryptomator.common.keychain;
import dagger.Module;
import dagger.Provides;
-import org.cryptomator.common.PluginClassLoader;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.integrations.keychain.KeychainAccessProvider;
import javax.inject.Singleton;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.ObjectExpression;
-import java.util.ServiceLoader;
-import java.util.Set;
-import java.util.stream.Collectors;
+import java.util.List;
@Module
public class KeychainModule {
@Provides
@Singleton
- static Set> provideAvailableKeychainAccessProviderFactories(PluginClassLoader classLoader) {
- return ServiceLoader.load(KeychainAccessProvider.class, classLoader).stream().collect(Collectors.toUnmodifiableSet());
+ static List provideSupportedKeychainAccessProviders() {
+ return KeychainAccessProvider.get().toList();
}
@Provides
@Singleton
- static Set provideSupportedKeychainAccessProviders(Set> availableFactories) {
- return availableFactories.stream() //
- .map(ServiceLoader.Provider::get) //
- .filter(KeychainAccessProvider::isSupported) //
- .collect(Collectors.toUnmodifiableSet());
- }
-
- @Provides
- @Singleton
- static ObjectExpression provideKeychainAccessProvider(Settings settings, Set providers) {
+ static ObjectExpression provideKeychainAccessProvider(Settings settings, List providers) {
return Bindings.createObjectBinding(() -> {
var selectedProviderClass = settings.keychainProvider().get();
var selectedProvider = providers.stream().filter(provider -> provider.getClass().getName().equals(selectedProviderClass)).findAny();
- var fallbackProvider = providers.stream().findAny().orElse(null);
+ var fallbackProvider = providers.stream().findFirst().orElse(null);
return selectedProvider.orElse(fallbackProvider);
}, settings.keychainProvider());
}
diff --git a/src/main/java/org/cryptomator/launcher/CryptomatorModule.java b/src/main/java/org/cryptomator/launcher/CryptomatorModule.java
index e6aab0309..42e908df2 100644
--- a/src/main/java/org/cryptomator/launcher/CryptomatorModule.java
+++ b/src/main/java/org/cryptomator/launcher/CryptomatorModule.java
@@ -2,7 +2,6 @@ package org.cryptomator.launcher;
import dagger.Module;
import dagger.Provides;
-import org.cryptomator.common.PluginClassLoader;
import org.cryptomator.integrations.autostart.AutoStartProvider;
import org.cryptomator.integrations.tray.TrayIntegrationProvider;
import org.cryptomator.integrations.uiappearance.UiAppearanceProvider;
@@ -12,7 +11,6 @@ import javax.inject.Named;
import javax.inject.Singleton;
import java.util.Optional;
import java.util.ResourceBundle;
-import java.util.ServiceLoader;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
@@ -32,25 +30,22 @@ class CryptomatorModule {
return new ArrayBlockingQueue<>(10);
}
- // TODO: still needed after integrations-api 1.1.0?
-
@Provides
@Singleton
- static Optional provideAppearanceProvider(PluginClassLoader classLoader) {
- return ServiceLoader.load(UiAppearanceProvider.class, classLoader).findFirst();
+ static Optional provideAppearanceProvider() {
+ return UiAppearanceProvider.get();
}
@Provides
@Singleton
- static Optional provideAutostartProvider(PluginClassLoader classLoader) {
- return ServiceLoader.load(AutoStartProvider.class, classLoader).findFirst();
+ static Optional provideAutostartProvider() {
+ return AutoStartProvider.get();
}
@Provides
@Singleton
- static Optional provideTrayIntegrationProvider(PluginClassLoader classLoader) {
- return ServiceLoader.load(TrayIntegrationProvider.class, classLoader).findFirst();
+ static Optional provideTrayIntegrationProvider() {
+ return TrayIntegrationProvider.get();
}
-
}
diff --git a/src/main/java/org/cryptomator/ui/addvaultwizard/ChooseExistingVaultController.java b/src/main/java/org/cryptomator/ui/addvaultwizard/ChooseExistingVaultController.java
index 01a8a6758..e9b5865d5 100644
--- a/src/main/java/org/cryptomator/ui/addvaultwizard/ChooseExistingVaultController.java
+++ b/src/main/java/org/cryptomator/ui/addvaultwizard/ChooseExistingVaultController.java
@@ -2,6 +2,8 @@ package org.cryptomator.ui.addvaultwizard;
import dagger.Lazy;
import org.apache.commons.lang3.SystemUtils;
+import org.cryptomator.common.settings.Settings;
+import org.cryptomator.common.settings.UiTheme;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultListManager;
import org.cryptomator.ui.common.FxController;
@@ -36,11 +38,12 @@ public class ChooseExistingVaultController implements FxController {
private final ObjectProperty vault;
private final VaultListManager vaultListManager;
private final ResourceBundle resourceBundle;
+ private final Settings settings;
private Image screenshot;
@Inject
- ChooseExistingVaultController(@AddVaultWizardWindow Stage window, @FxmlScene(FxmlFile.ADDVAULT_WELCOME) Lazy welcomeScene, @FxmlScene(FxmlFile.ADDVAULT_SUCCESS) Lazy successScene, FxApplicationWindows appWindows, ObjectProperty vaultPath, @AddVaultWizardWindow ObjectProperty vault, VaultListManager vaultListManager, ResourceBundle resourceBundle) {
+ ChooseExistingVaultController(@AddVaultWizardWindow Stage window, @FxmlScene(FxmlFile.ADDVAULT_WELCOME) Lazy welcomeScene, @FxmlScene(FxmlFile.ADDVAULT_SUCCESS) Lazy successScene, FxApplicationWindows appWindows, ObjectProperty vaultPath, @AddVaultWizardWindow ObjectProperty vault, VaultListManager vaultListManager, ResourceBundle resourceBundle, Settings settings) {
this.window = window;
this.welcomeScene = welcomeScene;
this.successScene = successScene;
@@ -49,12 +52,13 @@ public class ChooseExistingVaultController implements FxController {
this.vault = vault;
this.vaultListManager = vaultListManager;
this.resourceBundle = resourceBundle;
+ this.settings = settings;
}
@FXML
public void initialize() {
if (SystemUtils.IS_OS_MAC) {
- this.screenshot = new Image(getClass().getResource("/img/select-masterkey-mac.png").toString());
+ this.screenshot = new Image(getClass().getResource("/img/select-masterkey-mac"+(UiTheme.LIGHT == settings.theme().get()? "":"-dark")+".png").toString());
} else {
this.screenshot = new Image(getClass().getResource("/img/select-masterkey-win.png").toString());
}
diff --git a/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java b/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java
index 51a8a1147..c6bfb3f0e 100644
--- a/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java
+++ b/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java
@@ -121,16 +121,6 @@ public class CreateNewVaultPasswordController implements FxController {
@FXML
public void next() {
- Path pathToVault = vaultPathProperty.get();
-
- try {
- Files.createDirectory(pathToVault);
- } catch (IOException e) {
- LOG.error("Failed to create vault directory.", e);
- appWindows.showErrorWindow(e, window, window.getScene());
- return;
- }
-
if (showRecoveryKey.equals(recoveryKeyChoice.getSelectedToggle())) {
showRecoveryKeyScene();
} else if (skipRecoveryKey.equals(recoveryKeyChoice.getSelectedToggle())) {
@@ -144,14 +134,14 @@ public class CreateNewVaultPasswordController implements FxController {
Path pathToVault = vaultPathProperty.get();
processing.set(true);
Tasks.create(() -> {
- initializeVault(pathToVault);
+ createVault(pathToVault);
return recoveryKeyFactory.createRecoveryKey(pathToVault, newPasswordSceneController.passwordField.getCharacters());
}).onSuccess(recoveryKey -> {
- initializationSucceeded(pathToVault);
+ creationSucceeded(pathToVault);
recoveryKeyProperty.set(recoveryKey);
window.setScene(recoveryKeyScene.get());
}).onError(IOException.class, e -> {
- LOG.error("Failed to initialize vault.", e);
+ LOG.error("Failed to create vault.", e);
appWindows.showErrorWindow(e, window, window.getScene());
}).andFinally(() -> {
processing.set(false);
@@ -162,19 +152,22 @@ public class CreateNewVaultPasswordController implements FxController {
Path pathToVault = vaultPathProperty.get();
processing.set(true);
Tasks.create(() -> {
- initializeVault(pathToVault);
+ createVault(pathToVault);
}).onSuccess(() -> {
- initializationSucceeded(pathToVault);
+ creationSucceeded(pathToVault);
window.setScene(successScene.get());
}).onError(IOException.class, e -> {
- LOG.error("Failed to initialize vault.", e);
+ LOG.error("Failed to create vault.", e);
appWindows.showErrorWindow(e, window, window.getScene());
}).andFinally(() -> {
processing.set(false);
}).runOnce(executor);
}
- private void initializeVault(Path path) throws IOException {
+ private void createVault(Path path) throws IOException {
+ // 0. create directory
+ Files.createDirectory(path);
+
// 1. write masterkey:
Path masterkeyFilePath = path.resolve(MASTERKEY_FILENAME);
try (Masterkey masterkey = Masterkey.generate(csprng)) {
@@ -193,7 +186,7 @@ public class CreateNewVaultPasswordController implements FxController {
ch.write(US_ASCII.encode(readmeGenerator.createVaultAccessLocationReadmeRtf()));
}
} catch (CryptoException e) {
- throw new IOException("Failed initialize vault.", e);
+ throw new IOException("Vault initialization failed", e);
}
}
@@ -206,7 +199,7 @@ public class CreateNewVaultPasswordController implements FxController {
LOG.info("Created vault at {}", path);
}
- private void initializationSucceeded(Path pathToVault) {
+ private void creationSucceeded(Path pathToVault) {
try {
Vault newVault = vaultListManager.add(pathToVault);
vaultProperty.set(newVault);
diff --git a/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java b/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java
index fd9326c3d..3ddb7cba6 100644
--- a/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java
+++ b/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java
@@ -9,11 +9,6 @@ import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Named;
import javafx.application.Platform;
-import javafx.stage.Stage;
-import javafx.stage.StageStyle;
-import java.awt.SystemTray;
-import java.io.IOException;
-import java.io.UncheckedIOException;
@FxApplicationScoped
public class FxApplication {
@@ -49,7 +44,7 @@ public class FxApplication {
// init system tray
final boolean hasTrayIcon;
- if (SystemTray.isSupported() && settings.showTrayIcon().get()) {
+ if (settings.showTrayIcon().get() && trayMenu.get().isSupported()) {
trayMenu.get().initializeTrayIcon();
Platform.setImplicitExit(false); // don't quit when closing all windows
hasTrayIcon = true;
diff --git a/src/main/java/org/cryptomator/ui/fxapp/FxApplicationStyle.java b/src/main/java/org/cryptomator/ui/fxapp/FxApplicationStyle.java
index da2a4a800..711da7948 100644
--- a/src/main/java/org/cryptomator/ui/fxapp/FxApplicationStyle.java
+++ b/src/main/java/org/cryptomator/ui/fxapp/FxApplicationStyle.java
@@ -83,12 +83,26 @@ public class FxApplicationStyle {
}
private void applyLightTheme() {
- Application.setUserAgentStylesheet(getClass().getResource("/css/light_theme.css").toString());
- appearanceProvider.ifPresent(provider -> provider.adjustToTheme(Theme.LIGHT));
+ var stylesheet = Optional //
+ .ofNullable(getClass().getResource("/css/light_theme.bss")) //
+ .orElse(getClass().getResource("/css/light_theme.css"));
+ if (stylesheet == null) {
+ LOG.warn("Failed to load light_theme stylesheet");
+ } else {
+ Application.setUserAgentStylesheet(stylesheet.toString());
+ appearanceProvider.ifPresent(provider -> provider.adjustToTheme(Theme.LIGHT));
+ }
}
private void applyDarkTheme() {
- Application.setUserAgentStylesheet(getClass().getResource("/css/dark_theme.css").toString());
- appearanceProvider.ifPresent(provider -> provider.adjustToTheme(Theme.DARK));
+ var stylesheet = Optional //
+ .ofNullable(getClass().getResource("/css/dark_theme.bss")) //
+ .orElse(getClass().getResource("/css/dark_theme.css"));
+ if (stylesheet == null) {
+ LOG.warn("Failed to load dark_theme stylesheet");
+ } else {
+ Application.setUserAgentStylesheet(stylesheet.toString());
+ appearanceProvider.ifPresent(provider -> provider.adjustToTheme(Theme.DARK));
+ }
}
}
diff --git a/src/main/java/org/cryptomator/ui/mainwindow/MainWindowTitleController.java b/src/main/java/org/cryptomator/ui/mainwindow/MainWindowTitleController.java
index 76eee0cb4..70dea5366 100644
--- a/src/main/java/org/cryptomator/ui/mainwindow/MainWindowTitleController.java
+++ b/src/main/java/org/cryptomator/ui/mainwindow/MainWindowTitleController.java
@@ -116,7 +116,7 @@ public class MainWindowTitleController implements FxController {
}
@FXML
- public void showDonationKeyPreferences() {
+ public void showContributePreferences() {
appWindows.showPreferencesWindow(SelectedPreferencesTab.CONTRIBUTE);
}
diff --git a/src/main/java/org/cryptomator/ui/preferences/AboutController.java b/src/main/java/org/cryptomator/ui/preferences/AboutController.java
index 758e0113b..f418843ee 100644
--- a/src/main/java/org/cryptomator/ui/preferences/AboutController.java
+++ b/src/main/java/org/cryptomator/ui/preferences/AboutController.java
@@ -29,10 +29,10 @@ public class AboutController implements FxController {
}
private static String loadThirdPartyLicenseFile() {
- try (InputStream in = AboutController.class.getResourceAsStream("/license/THIRD-PARTY.txt")) {
+ try (InputStream in = AboutController.class.getResourceAsStream("/THIRD-PARTY.txt")) {
return CharStreams.toString(new InputStreamReader(in));
} catch (IOException | NullPointerException e) {
- LOG.error("Failed to load /license/THIRD-PARTY.txt", e);
+ LOG.error("Failed to load /THIRD-PARTY.txt", e);
return "";
}
}
diff --git a/src/main/java/org/cryptomator/ui/preferences/GeneralPreferencesController.java b/src/main/java/org/cryptomator/ui/preferences/GeneralPreferencesController.java
index f2b7ef3b7..d33e919b6 100644
--- a/src/main/java/org/cryptomator/ui/preferences/GeneralPreferencesController.java
+++ b/src/main/java/org/cryptomator/ui/preferences/GeneralPreferencesController.java
@@ -19,8 +19,8 @@ import javafx.scene.control.ChoiceBox;
import javafx.scene.control.ToggleGroup;
import javafx.stage.Stage;
import javafx.util.StringConverter;
+import java.util.List;
import java.util.Optional;
-import java.util.Set;
@PreferencesScoped
public class GeneralPreferencesController implements FxController {
@@ -32,7 +32,7 @@ public class GeneralPreferencesController implements FxController {
private final Optional autoStartProvider;
private final Application application;
private final Environment environment;
- private final Set keychainAccessProviders;
+ private final List keychainAccessProviders;
private final FxApplicationWindows appWindows;
public ChoiceBox keychainBackendChoiceBox;
public CheckBox startHiddenCheckbox;
@@ -41,7 +41,7 @@ public class GeneralPreferencesController implements FxController {
public ToggleGroup nodeOrientation;
@Inject
- GeneralPreferencesController(@PreferencesWindow Stage window, Settings settings, Optional autoStartProvider, Set keychainAccessProviders, Application application, Environment environment, FxApplicationWindows appWindows) {
+ GeneralPreferencesController(@PreferencesWindow Stage window, Settings settings, Optional autoStartProvider, List keychainAccessProviders, Application application, Environment environment, FxApplicationWindows appWindows) {
this.window = window;
this.settings = settings;
this.autoStartProvider = autoStartProvider;
@@ -115,9 +115,9 @@ public class GeneralPreferencesController implements FxController {
private static class KeychainProviderClassNameConverter extends StringConverter {
- private final Set keychainAccessProviders;
+ private final List keychainAccessProviders;
- public KeychainProviderClassNameConverter(Set keychainAccessProviders) {
+ public KeychainProviderClassNameConverter(List keychainAccessProviders) {
this.keychainAccessProviders = keychainAccessProviders;
}
diff --git a/src/main/java/org/cryptomator/ui/preferences/VolumePreferencesController.java b/src/main/java/org/cryptomator/ui/preferences/VolumePreferencesController.java
index 4af86dc85..8f9f6f6da 100644
--- a/src/main/java/org/cryptomator/ui/preferences/VolumePreferencesController.java
+++ b/src/main/java/org/cryptomator/ui/preferences/VolumePreferencesController.java
@@ -48,6 +48,11 @@ public class VolumePreferencesController implements FxController {
webDavPortField.setText(String.valueOf(settings.port().get()));
changeWebDavPortButton.visibleProperty().bind(settings.port().asString().isNotEqualTo(webDavPortField.textProperty()));
changeWebDavPortButton.disableProperty().bind(Bindings.createBooleanBinding(this::validateWebDavPort, webDavPortField.textProperty()).not());
+ webDavPortField.focusedProperty().addListener((observableValue, wasFocused, isFocused) -> {
+ if(!isFocused) {
+ webDavPortField.setText(String.valueOf(settings.port().get()));
+ }
+ });
webDavUrlSchemeChoiceBox.getItems().addAll(WebDavUrlScheme.values());
webDavUrlSchemeChoiceBox.valueProperty().bindBidirectional(settings.preferredGvfsScheme());
diff --git a/src/main/java/org/cryptomator/ui/traymenu/AwtTrayMenuController.java b/src/main/java/org/cryptomator/ui/traymenu/AwtTrayMenuController.java
new file mode 100644
index 000000000..79f1dd628
--- /dev/null
+++ b/src/main/java/org/cryptomator/ui/traymenu/AwtTrayMenuController.java
@@ -0,0 +1,79 @@
+package org.cryptomator.ui.traymenu;
+
+import org.apache.commons.lang3.SystemUtils;
+import org.cryptomator.integrations.common.CheckAvailability;
+import org.cryptomator.integrations.common.Priority;
+import org.cryptomator.integrations.tray.ActionItem;
+import org.cryptomator.integrations.tray.SeparatorItem;
+import org.cryptomator.integrations.tray.SubMenuItem;
+import org.cryptomator.integrations.tray.TrayMenuController;
+import org.cryptomator.integrations.tray.TrayMenuException;
+import org.cryptomator.integrations.tray.TrayMenuItem;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.awt.AWTException;
+import java.awt.Menu;
+import java.awt.MenuItem;
+import java.awt.PopupMenu;
+import java.awt.SystemTray;
+import java.awt.Toolkit;
+import java.awt.TrayIcon;
+import java.util.List;
+
+@CheckAvailability
+@Priority(Priority.FALLBACK)
+public class AwtTrayMenuController implements TrayMenuController {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AwtTrayMenuController.class);
+
+ private final PopupMenu menu = new PopupMenu();
+
+ @CheckAvailability
+ public static boolean isAvailable() {
+ return SystemTray.isSupported();
+ }
+
+ @Override
+ public void showTrayIcon(byte[] rawImageData, Runnable defaultAction, String tooltip) throws TrayMenuException {
+ var image = Toolkit.getDefaultToolkit().createImage(rawImageData);
+ var trayIcon = new TrayIcon(image, tooltip, menu);
+
+ trayIcon.setImageAutoSize(true);
+ if (SystemUtils.IS_OS_WINDOWS) {
+ trayIcon.addActionListener(evt -> defaultAction.run());
+ }
+
+ try {
+ SystemTray.getSystemTray().add(trayIcon);
+ LOG.debug("initialized tray icon");
+ } catch (AWTException e) {
+ throw new TrayMenuException("Failed to add icon to system tray.", e);
+ }
+ }
+
+ @Override
+ public void updateTrayMenu(List items) {
+ menu.removeAll();
+ addChildren(menu, items);
+ }
+
+ private void addChildren(Menu menu, List items) {
+ for (var item : items) {
+ // TODO: use Pattern Matching for switch, once available
+ if (item instanceof ActionItem a) {
+ var menuItem = new MenuItem(a.title());
+ menuItem.addActionListener(evt -> a.action().run());
+ menuItem.setEnabled(a.enabled());
+ menu.add(menuItem);
+ } else if (item instanceof SeparatorItem) {
+ menu.addSeparator();
+ } else if (item instanceof SubMenuItem s) {
+ var submenu = new Menu(s.title());
+ addChildren(submenu, s.items());
+ menu.add(submenu);
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/org/cryptomator/ui/traymenu/TrayIconController.java b/src/main/java/org/cryptomator/ui/traymenu/TrayIconController.java
deleted file mode 100644
index 2c176df76..000000000
--- a/src/main/java/org/cryptomator/ui/traymenu/TrayIconController.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package org.cryptomator.ui.traymenu;
-
-import com.google.common.base.Preconditions;
-import org.apache.commons.lang3.SystemUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.inject.Inject;
-import java.awt.AWTException;
-import java.awt.SystemTray;
-import java.awt.TrayIcon;
-
-@TrayMenuScoped
-public class TrayIconController {
-
- private static final Logger LOG = LoggerFactory.getLogger(TrayIconController.class);
-
- private final TrayMenuController trayMenuController;
- private final TrayIcon trayIcon;
- private volatile boolean initialized;
-
- @Inject
- TrayIconController(TrayImageFactory imageFactory, TrayMenuController trayMenuController) {
- this.trayMenuController = trayMenuController;
- this.trayIcon = new TrayIcon(imageFactory.loadImage(), "Cryptomator", trayMenuController.getMenu());
- }
-
- public synchronized void initializeTrayIcon() throws IllegalStateException {
- Preconditions.checkState(!initialized);
-
- trayIcon.setImageAutoSize(true);
- if (SystemUtils.IS_OS_WINDOWS) {
- trayIcon.addActionListener(trayMenuController::showMainWindow);
- }
-
- try {
- SystemTray.getSystemTray().add(trayIcon);
- LOG.debug("initialized tray icon");
- } catch (AWTException e) {
- LOG.error("Error adding tray icon", e);
- }
-
- trayMenuController.initTrayMenu();
-
- this.initialized = true;
- }
-
- public boolean isInitialized() {
- return initialized;
- }
-}
diff --git a/src/main/java/org/cryptomator/ui/traymenu/TrayImageFactory.java b/src/main/java/org/cryptomator/ui/traymenu/TrayImageFactory.java
deleted file mode 100644
index aa55ca766..000000000
--- a/src/main/java/org/cryptomator/ui/traymenu/TrayImageFactory.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package org.cryptomator.ui.traymenu;
-
-import org.apache.commons.lang3.SystemUtils;
-import org.cryptomator.integrations.uiappearance.Theme;
-import org.cryptomator.integrations.uiappearance.UiAppearanceProvider;
-
-import javax.inject.Inject;
-import java.awt.Image;
-import java.awt.Toolkit;
-import java.util.Optional;
-
-@TrayMenuScoped
-class TrayImageFactory {
-
- private final Optional appearanceProvider;
-
- @Inject
- TrayImageFactory(Optional appearanceProvider) {
- this.appearanceProvider = appearanceProvider;
- }
-
- public Image loadImage() {
- String resourceName = SystemUtils.IS_OS_MAC_OSX ? getMacResourceName() : getWinOrLinuxResourceName();
- return Toolkit.getDefaultToolkit().getImage(getClass().getResource(resourceName));
- }
-
- private String getMacResourceName() {
- return "/img/tray_icon_mac.png";
- }
-
- private String getWinOrLinuxResourceName() {
- return "/img/tray_icon.png";
- }
-
-}
diff --git a/src/main/java/org/cryptomator/ui/traymenu/TrayMenuBuilder.java b/src/main/java/org/cryptomator/ui/traymenu/TrayMenuBuilder.java
new file mode 100644
index 000000000..ea8599b51
--- /dev/null
+++ b/src/main/java/org/cryptomator/ui/traymenu/TrayMenuBuilder.java
@@ -0,0 +1,151 @@
+package org.cryptomator.ui.traymenu;
+
+import com.google.common.base.Preconditions;
+import org.apache.commons.lang3.SystemUtils;
+import org.cryptomator.common.vaults.Vault;
+import org.cryptomator.integrations.tray.ActionItem;
+import org.cryptomator.integrations.tray.SeparatorItem;
+import org.cryptomator.integrations.tray.SubMenuItem;
+import org.cryptomator.integrations.tray.TrayMenuController;
+import org.cryptomator.integrations.tray.TrayMenuException;
+import org.cryptomator.integrations.tray.TrayMenuItem;
+import org.cryptomator.ui.common.VaultService;
+import org.cryptomator.ui.fxapp.FxApplicationTerminator;
+import org.cryptomator.ui.fxapp.FxApplicationWindows;
+import org.cryptomator.ui.preferences.SelectedPreferencesTab;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import javafx.application.Platform;
+import javafx.beans.Observable;
+import javafx.collections.ObservableList;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.ResourceBundle;
+
+@TrayMenuScoped
+public class TrayMenuBuilder {
+
+ private static final Logger LOG = LoggerFactory.getLogger(TrayMenuBuilder.class);
+ private static final String TRAY_ICON_MAC = "/img/tray_icon_mac.png";
+ private static final String TRAY_ICON = "/img/tray_icon.png";
+
+ private final ResourceBundle resourceBundle;
+ private final VaultService vaultService;
+ private final FxApplicationWindows appWindows;
+ private final FxApplicationTerminator appTerminator;
+ private final ObservableList vaults;
+ private final TrayMenuController trayMenu;
+
+ private volatile boolean initialized;
+
+ @Inject
+ TrayMenuBuilder(ResourceBundle resourceBundle, VaultService vaultService, FxApplicationWindows appWindows, FxApplicationTerminator appTerminator, ObservableList vaults, Optional trayMenu) {
+ this.resourceBundle = resourceBundle;
+ this.vaultService = vaultService;
+ this.appWindows = appWindows;
+ this.appTerminator = appTerminator;
+ this.vaults = vaults;
+ this.trayMenu = trayMenu.orElse(null);
+ }
+
+ public synchronized void initTrayMenu() {
+ Preconditions.checkState(!initialized, "tray icon already initialized");
+
+ vaults.addListener(this::vaultListChanged);
+ vaults.forEach(v -> {
+ v.displayNameProperty().addListener(this::vaultListChanged);
+ });
+
+ try (var image = getClass().getResourceAsStream(SystemUtils.IS_OS_MAC_OSX ? TRAY_ICON_MAC : TRAY_ICON)) {
+ trayMenu.showTrayIcon(image.readAllBytes(), this::showMainWindow, "Cryptomator");
+ rebuildMenu();
+ initialized = true;
+ } catch (IOException e) {
+ throw new UncheckedIOException("Failed to load embedded resource", e);
+ } catch (TrayMenuException e) {
+ LOG.error("Adding tray icon failed", e);
+ }
+ }
+
+ public boolean isInitialized() {
+ return initialized;
+ }
+
+ private void vaultListChanged(@SuppressWarnings("unused") Observable observable) {
+ assert Platform.isFxApplicationThread();
+ rebuildMenu();
+ }
+
+ private void rebuildMenu() {
+ List menu = new ArrayList<>();
+
+ menu.add(new ActionItem(resourceBundle.getString("traymenu.showMainWindow"), this::showMainWindow));
+ menu.add(new ActionItem(resourceBundle.getString("traymenu.showPreferencesWindow"), this::showPreferencesWindow));
+ menu.add(new SeparatorItem());
+ for (Vault vault : vaults) {
+ List submenu = buildSubmenu(vault);
+ var label = vault.isUnlocked() ? "* ".concat(vault.getDisplayName()) : vault.getDisplayName();
+ menu.add(new SubMenuItem(label, submenu));
+ }
+ menu.add(new SeparatorItem());
+ menu.add(new ActionItem(resourceBundle.getString("traymenu.lockAllVaults"), this::lockAllVaults, vaults.stream().anyMatch(Vault::isUnlocked)));
+ menu.add(new ActionItem(resourceBundle.getString("traymenu.quitApplication"), this::quitApplication));
+
+ try {
+ trayMenu.updateTrayMenu(menu);
+ } catch (TrayMenuException e) {
+ LOG.error("Updating tray menu failed", e);
+ }
+ }
+
+ private List buildSubmenu(Vault vault) {
+ if (vault.isLocked()) {
+ return List.of( //
+ new ActionItem(resourceBundle.getString("traymenu.vault.unlock"), () -> this.unlockVault(vault)) //
+ );
+ } else if (vault.isUnlocked()) {
+ return List.of( //
+ new ActionItem(resourceBundle.getString("traymenu.vault.lock"), () -> this.lockVault(vault)), //
+ new ActionItem(resourceBundle.getString("traymenu.vault.reveal"), () -> this.revealVault(vault)) //
+ );
+ } else {
+ return List.of();
+ }
+ }
+
+ /* action listeners: */
+
+ private void quitApplication() {
+ appTerminator.terminate();
+ }
+
+ private void unlockVault(Vault vault) {
+ appWindows.startUnlockWorkflow(vault, null);
+ }
+
+ private void lockVault(Vault vault) {
+ appWindows.startLockWorkflow(vault, null);
+ }
+
+ private void lockAllVaults() {
+ vaultService.lockAll(vaults.filtered(Vault::isUnlocked), false);
+ }
+
+ private void revealVault(Vault vault) {
+ vaultService.reveal(vault);
+ }
+
+ void showMainWindow() {
+ appWindows.showMainWindow();
+ }
+
+ private void showPreferencesWindow() {
+ appWindows.showPreferencesWindow(SelectedPreferencesTab.ANY);
+ }
+
+}
diff --git a/src/main/java/org/cryptomator/ui/traymenu/TrayMenuComponent.java b/src/main/java/org/cryptomator/ui/traymenu/TrayMenuComponent.java
index c4cbfd456..02bf2aabd 100644
--- a/src/main/java/org/cryptomator/ui/traymenu/TrayMenuComponent.java
+++ b/src/main/java/org/cryptomator/ui/traymenu/TrayMenuComponent.java
@@ -5,38 +5,44 @@
*******************************************************************************/
package org.cryptomator.ui.traymenu;
-import dagger.Lazy;
+import com.google.common.base.Preconditions;
import dagger.Subcomponent;
-import java.awt.SystemTray;
+import org.cryptomator.integrations.tray.TrayMenuController;
+
+import java.util.Optional;
@TrayMenuScoped
-@Subcomponent
+@Subcomponent(modules = {TrayMenuModule.class})
public interface TrayMenuComponent {
- Lazy trayIconController();
+ Optional trayMenuController();
+
+ TrayMenuBuilder trayMenuBuilder();
/**
* @return true if a tray icon can be installed
*/
default boolean isSupported() {
- return SystemTray.isSupported();
+ return trayMenuController().isPresent();
}
/**
* @return true if a tray icon has been installed
*/
default boolean isInitialized() {
- return isSupported() && trayIconController().get().isInitialized();
+ return isSupported() && trayMenuBuilder().isInitialized();
}
/**
* Installs a tray icon to the system tray.
*
- * @throws IllegalStateException If already added
+ * @throws IllegalStateException If not {@link #isSupported() supported}
*/
default void initializeTrayIcon() throws IllegalStateException {
- assert isSupported();
- trayIconController().get().initializeTrayIcon();
+ Preconditions.checkState(isSupported(), "system tray not supported");
+ if (!trayMenuBuilder().isInitialized()) {
+ trayMenuBuilder().initTrayMenu();
+ }
}
@Subcomponent.Builder
diff --git a/src/main/java/org/cryptomator/ui/traymenu/TrayMenuController.java b/src/main/java/org/cryptomator/ui/traymenu/TrayMenuController.java
deleted file mode 100644
index 32f6cbc52..000000000
--- a/src/main/java/org/cryptomator/ui/traymenu/TrayMenuController.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package org.cryptomator.ui.traymenu;
-
-import org.cryptomator.common.vaults.Vault;
-import org.cryptomator.ui.common.VaultService;
-import org.cryptomator.ui.fxapp.FxApplicationTerminator;
-import org.cryptomator.ui.fxapp.FxApplicationWindows;
-import org.cryptomator.ui.preferences.SelectedPreferencesTab;
-
-import javax.inject.Inject;
-import javafx.application.Platform;
-import javafx.beans.Observable;
-import javafx.collections.ObservableList;
-import java.awt.Menu;
-import java.awt.MenuItem;
-import java.awt.PopupMenu;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.util.EventObject;
-import java.util.ResourceBundle;
-import java.util.function.Consumer;
-
-@TrayMenuScoped
-class TrayMenuController {
-
- private final ResourceBundle resourceBundle;
- private final VaultService vaultService;
- private final FxApplicationWindows appWindows;
- private final FxApplicationTerminator appTerminator;
- private final ObservableList vaults;
- private final PopupMenu menu;
-
- @Inject
- TrayMenuController(ResourceBundle resourceBundle, VaultService vaultService, FxApplicationWindows appWindows, FxApplicationTerminator appTerminator, ObservableList vaults) {
- this.resourceBundle = resourceBundle;
- this.vaultService = vaultService;
- this.appWindows = appWindows;
- this.appTerminator = appTerminator;
- this.vaults = vaults;
- this.menu = new PopupMenu();
- }
-
- public PopupMenu getMenu() {
- return menu;
- }
-
- public void initTrayMenu() {
- vaults.addListener(this::vaultListChanged);
- vaults.forEach(v -> {
- v.displayNameProperty().addListener(this::vaultListChanged);
- });
- rebuildMenu();
- }
-
- private void vaultListChanged(@SuppressWarnings("unused") Observable observable) {
- assert Platform.isFxApplicationThread();
- rebuildMenu();
- }
-
- private void rebuildMenu() {
- menu.removeAll();
-
- MenuItem showMainWindowItem = new MenuItem(resourceBundle.getString("traymenu.showMainWindow"));
- showMainWindowItem.addActionListener(this::showMainWindow);
- menu.add(showMainWindowItem);
-
- MenuItem showPreferencesItem = new MenuItem(resourceBundle.getString("traymenu.showPreferencesWindow"));
- showPreferencesItem.addActionListener(this::showPreferencesWindow);
- menu.add(showPreferencesItem);
-
- menu.addSeparator();
- for (Vault v : vaults) {
- MenuItem submenu = buildSubmenu(v);
- menu.add(submenu);
- }
- menu.addSeparator();
-
- MenuItem lockAllItem = new MenuItem(resourceBundle.getString("traymenu.lockAllVaults"));
- lockAllItem.addActionListener(this::lockAllVaults);
- lockAllItem.setEnabled(!vaults.filtered(Vault::isUnlocked).isEmpty());
- menu.add(lockAllItem);
-
- MenuItem quitApplicationItem = new MenuItem(resourceBundle.getString("traymenu.quitApplication"));
- quitApplicationItem.addActionListener(this::quitApplication);
- menu.add(quitApplicationItem);
- }
-
- private Menu buildSubmenu(Vault vault) {
- Menu submenu = new Menu(vault.getDisplayName());
-
- if (vault.isLocked()) {
- MenuItem unlockItem = new MenuItem(resourceBundle.getString("traymenu.vault.unlock"));
- unlockItem.addActionListener(createActionListenerForVault(vault, this::unlockVault));
- submenu.add(unlockItem);
- } else if (vault.isUnlocked()) {
- submenu.setLabel("* ".concat(submenu.getLabel()));
-
- MenuItem lockItem = new MenuItem(resourceBundle.getString("traymenu.vault.lock"));
- lockItem.addActionListener(createActionListenerForVault(vault, this::lockVault));
- submenu.add(lockItem);
-
- MenuItem revealItem = new MenuItem(resourceBundle.getString("traymenu.vault.reveal"));
- revealItem.addActionListener(createActionListenerForVault(vault, this::revealVault));
- submenu.add(revealItem);
- }
-
- return submenu;
- }
-
- private ActionListener createActionListenerForVault(Vault vault, Consumer consumer) {
- return actionEvent -> consumer.accept(vault);
- }
-
- private void quitApplication(EventObject actionEvent) {
- appTerminator.terminate();
- }
-
- private void unlockVault(Vault vault) {
- appWindows.startUnlockWorkflow(vault, null);
- }
-
- private void lockVault(Vault vault) {
- appWindows.startLockWorkflow(vault, null);
- }
-
- private void lockAllVaults(ActionEvent actionEvent) {
- vaultService.lockAll(vaults.filtered(Vault::isUnlocked), false);
- }
-
- private void revealVault(Vault vault) {
- vaultService.reveal(vault);
- }
-
- void showMainWindow(@SuppressWarnings("unused") ActionEvent actionEvent) {
- appWindows.showMainWindow();
- }
-
- private void showPreferencesWindow(@SuppressWarnings("unused") EventObject actionEvent) {
- appWindows.showPreferencesWindow(SelectedPreferencesTab.ANY);
- }
-
-}
diff --git a/src/main/java/org/cryptomator/ui/traymenu/TrayMenuModule.java b/src/main/java/org/cryptomator/ui/traymenu/TrayMenuModule.java
new file mode 100644
index 000000000..3110be883
--- /dev/null
+++ b/src/main/java/org/cryptomator/ui/traymenu/TrayMenuModule.java
@@ -0,0 +1,18 @@
+package org.cryptomator.ui.traymenu;
+
+import dagger.Module;
+import dagger.Provides;
+import org.cryptomator.integrations.tray.TrayMenuController;
+
+import java.util.Optional;
+
+@Module
+public class TrayMenuModule {
+
+ @Provides
+ @TrayMenuScoped
+ static Optional provideSupportedKeychainAccessProviders() {
+ return TrayMenuController.get();
+ }
+
+}
diff --git a/src/main/resources/fxml/main_window_title.fxml b/src/main/resources/fxml/main_window_title.fxml
index 108c0970e..734107e4f 100644
--- a/src/main/resources/fxml/main_window_title.fxml
+++ b/src/main/resources/fxml/main_window_title.fxml
@@ -32,7 +32,7 @@
-