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 + ")"> + + +{\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)}\ + + + +\ + +\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 ) "> -{\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 @@ -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 ) "> -{\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 \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 @@ -