mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-09-21 23:44:42 +00:00
Compare commits
172
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
845189c638 | ||
|
|
61b7a39aad | ||
|
|
16bd84ee62 | ||
|
|
3d0a97fcdf | ||
|
|
b199b65e38 | ||
|
|
999abf3c13 | ||
|
|
31e938de6a | ||
|
|
4c10ab764a | ||
|
|
4e075ab0ca | ||
|
|
f73ae9759f | ||
|
|
f6283b2f7e | ||
|
|
b23d2e4def | ||
|
|
91a2943599 | ||
|
|
e083fd0bcc | ||
|
|
ff687f1bae | ||
|
|
84d2644f19 | ||
|
|
f9a9d7b870 | ||
|
|
d75a8c4bba | ||
|
|
d326c7c990 | ||
|
|
e8e63ca4fc | ||
|
|
6878f2e94b | ||
|
|
a17b416262 | ||
|
|
fed572694f | ||
|
|
fe3d67d937 | ||
|
|
3dcdeb1033 | ||
|
|
0898158c5a | ||
|
|
81091d4bdf | ||
|
|
c9b1b1baa5 | ||
|
|
c81f3bd972 | ||
|
|
9f86b74320 | ||
|
|
2d8390a0f3 | ||
|
|
8d3671175f | ||
|
|
366011a222 | ||
|
|
c0c2e21055 | ||
|
|
63be96a151 | ||
|
|
fc1df4bd99 | ||
|
|
7657330931 | ||
|
|
4e44de3c3b | ||
|
|
8d902a72ca | ||
|
|
7378031a72 | ||
|
|
f898c07c27 | ||
|
|
c8f02d1045 | ||
|
|
4cc13b986b | ||
|
|
af7b6780f3 | ||
|
|
4a17d01004 | ||
|
|
1d68408e21 | ||
|
|
821b1ee660 | ||
|
|
c6616bd467 | ||
|
|
4bb2589f16 | ||
|
|
896c3b3565 | ||
|
|
6ee717a693 | ||
|
|
07ec858e1e | ||
|
|
a7c1e43ebc | ||
|
|
ac1cd3b073 | ||
|
|
7474519faf | ||
|
|
340e474c33 | ||
|
|
c90ab75427 | ||
|
|
848b3f77d3 | ||
|
|
fb8cdb31ca | ||
|
|
ba5f8053fb | ||
|
|
38165becca | ||
|
|
f731ac5c90 | ||
|
|
0291702736 | ||
|
|
ab63929861 | ||
|
|
ca36fb8af3 | ||
|
|
8cb29ff83b | ||
|
|
304fa67dd7 | ||
|
|
a80ec32d2c | ||
|
|
dc4f21162e | ||
|
|
3b8d7e0241 | ||
|
|
6891c68cf1 | ||
|
|
18b26fbc58 | ||
|
|
1db8da6b6b | ||
|
|
14bce7e91d | ||
|
|
2674bc6f23 | ||
|
|
74e1d6f991 | ||
|
|
25dba028f8 | ||
|
|
bf51cc13d1 | ||
|
|
24be36cccb | ||
|
|
797e15c775 | ||
|
|
2395dbcae9 | ||
|
|
efacbbe2b6 | ||
|
|
2518086e46 | ||
|
|
c733247611 | ||
|
|
4f44e71e13 | ||
|
|
02aa46ece8 | ||
|
|
635f64c847 | ||
|
|
0a8516ae9a | ||
|
|
c1edb30472 | ||
|
|
93c78b63ca | ||
|
|
3ccae93757 | ||
|
|
450dec2baf | ||
|
|
36121527ca | ||
|
|
f30451f7e1 | ||
|
|
74d7f63f64 | ||
|
|
350a4ab762 | ||
|
|
0e0e75b89c | ||
|
|
e76440d928 | ||
|
|
0cbace67a5 | ||
|
|
84a3082589 | ||
|
|
cdfcca06d1 | ||
|
|
630bfa4cee | ||
|
|
90cb7beb1f | ||
|
|
d37fa33278 | ||
|
|
eed9c906cc | ||
|
|
2b7ed5f4dd | ||
|
|
6a7a309a2b | ||
|
|
0382069995 | ||
|
|
7c5f40d7d1 | ||
|
|
09e9530660 | ||
|
|
947d25b335 | ||
|
|
80cbc6699a | ||
|
|
da0933fa92 | ||
|
|
adc9f32fb3 | ||
|
|
65369bdbff | ||
|
|
d18e618ef1 | ||
|
|
970216dd59 | ||
|
|
6840a649c7 | ||
|
|
e4709ed6fe | ||
|
|
19ebc7e562 | ||
|
|
0fa052d2d1 | ||
|
|
402861b9c0 | ||
|
|
aca1666dea | ||
|
|
70f6a4877c | ||
|
|
85c5dc8dfb | ||
|
|
23c113948f | ||
|
|
d86ea20c31 | ||
|
|
01929c2288 | ||
|
|
2634433b2c | ||
|
|
c1f44f76b9 | ||
|
|
b2f27c0a3d | ||
|
|
b1d7cfc81b | ||
|
|
7cd5c66836 | ||
|
|
95cef34234 | ||
|
|
8977440697 | ||
|
|
d5eb84a000 | ||
|
|
81fb6b8794 | ||
|
|
92b390d5bb | ||
|
|
8867532210 | ||
|
|
77db435b4f | ||
|
|
cb2bc17283 | ||
|
|
aaa93239d0 | ||
|
|
93445e22d4 | ||
|
|
64897cfa21 | ||
|
|
7349a29831 | ||
|
|
73554b4759 | ||
|
|
0312f045aa | ||
|
|
1134c1b2ff | ||
|
|
8bb925fd93 | ||
|
|
ca5d9eba36 | ||
|
|
1a49e24d8a | ||
|
|
24b0ed2502 | ||
|
|
a226d5403a | ||
|
|
0f3085cc73 | ||
|
|
f0a040cf29 | ||
|
|
0676748dde | ||
|
|
589b8384eb | ||
|
|
9e3947f337 | ||
|
|
790cc4e772 | ||
|
|
72f4988632 | ||
|
|
b3fa6bbf32 | ||
|
|
c2dc487c79 | ||
|
|
e74dd3be9e | ||
|
|
1eeee61572 | ||
|
|
984b7a2d0e | ||
|
|
45c714a123 | ||
|
|
96bb97d50a | ||
|
|
046acb9bbf | ||
|
|
ce4ec16c62 | ||
|
|
96c8c9a9a9 | ||
|
|
44db97327d | ||
|
|
f441700c25 |
@@ -5,28 +5,12 @@ labels: type:bug
|
||||
---
|
||||
|
||||
<!--
|
||||
**************************************
|
||||
* *
|
||||
* ⚠️⚠️⚠️ READ CAREFULLY ⚠️⚠️⚠️ *
|
||||
* *
|
||||
**************************************
|
||||
Do you want to ask a QUESTION? Are you looking for SUPPORT?
|
||||
We're happy to help you via our support channels! Please read: https://github.com/cryptomator/cryptomator/blob/develop/SUPPORT.md
|
||||
|
||||
By filing an issue, you are expected to comply with our code of conduct: https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md
|
||||
|
||||
Of course, we also expect you to search for existing similar issues first! ;) https://github.com/cryptomator/cryptomator/issues?q=
|
||||
|
||||
Please make sure to:
|
||||
- Comply with our code of conduct: https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md
|
||||
- Search for existing similar issues first: https://github.com/cryptomator/cryptomator/issues?q=
|
||||
|
||||
⚠️ IMPORTANT: If you don't stick to this template, the issue will get closed.
|
||||
|
||||
*****************************************************************************
|
||||
* *
|
||||
* To proof that you read this, please remove the X from the line below: *
|
||||
* *
|
||||
*****************************************************************************
|
||||
-->
|
||||
<!-- oooXooo -->
|
||||
|
||||
### Description
|
||||
|
||||
@@ -34,7 +18,7 @@ Of course, we also expect you to search for existing similar issues first! ;) ht
|
||||
|
||||
### System Setup
|
||||
|
||||
* Operating system and version: [Windows/macOS/Linux + Version]
|
||||
* Operating system and version: [Windows/macOS/Linux + Version ( + Desktop Environment, if Linux)]
|
||||
* Cryptomator version: [Shown in the settings]
|
||||
* Volume type: [Dokany/FUSE/WebDAV, shown in the settings]
|
||||
|
||||
@@ -61,7 +45,6 @@ Of course, we also expect you to search for existing similar issues first! ;) ht
|
||||
[Any additional information, log files, screenshots, configuration, or data that might be necessary to reproduce the issue.]
|
||||
|
||||
<!--
|
||||
|
||||
If you want to add the log file or screenshots, please add them as attachments. If your log file seems empty and doesn't show any errors, you may enable the debug mode first. Here is how to do that: https://community.cryptomator.org/t/how-do-i-enable-debug-mode/36
|
||||
|
||||
Then reproduce the problem to ensure all important information is contained in there. You may use test data or redact sensitive information from the log file.
|
||||
@@ -70,5 +53,4 @@ Log file location:
|
||||
- Windows: %appdata%/Cryptomator
|
||||
- macOS: ~/Library/Logs/Cryptomator
|
||||
- Linux: ~/.local/share/Cryptomator/logs
|
||||
|
||||
-->
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Cryptomator Community
|
||||
- name: Help & Support
|
||||
url: https://community.cryptomator.org/
|
||||
about: Please ask and answer questions here
|
||||
- name: Documentation
|
||||
about: You will find answers in our community forum
|
||||
- name: User Manual
|
||||
url: https://docs.cryptomator.org/
|
||||
about: Get instructions on how to use Cryptomator
|
||||
about: Read the Cryptomator documentation here
|
||||
|
||||
@@ -5,14 +5,9 @@ labels: type:feature-request
|
||||
---
|
||||
|
||||
<!--
|
||||
|
||||
Do you want to ask a QUESTION? Are you looking for SUPPORT?
|
||||
We're happy to help you via our support channels! Please read: https://github.com/cryptomator/cryptomator/blob/develop/SUPPORT.md
|
||||
|
||||
By filing a feature request, you are expected to comply with our code of conduct: https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md
|
||||
|
||||
Of course, we also expect you to search for existing similar feature requests first! ;)
|
||||
|
||||
Please make sure to:
|
||||
- Comply with our code of conduct: https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md
|
||||
- Search for existing similar issues first: https://github.com/cryptomator/cryptomator/issues?q=
|
||||
-->
|
||||
|
||||
### Summary
|
||||
@@ -29,4 +24,4 @@ Of course, we also expect you to search for existing similar feature requests fi
|
||||
|
||||
### Additional Context
|
||||
|
||||
[Add any other context or screenshots about the feature request here.]
|
||||
[Add any other context or screenshots about the feature request here.]
|
||||
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 14
|
||||
java-version: 16
|
||||
- uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
@@ -25,12 +25,13 @@ jobs:
|
||||
- name: Build and Test
|
||||
run: mvn -B install --file main/pom.xml -Pcoverage
|
||||
- name: Run Codacy Coverage Reporter
|
||||
if: github.repository == 'cryptomator/cryptomator'
|
||||
run: |
|
||||
curl -o ~/codacy-coverage-reporter.jar https://repo.maven.apache.org/maven2/com/codacy/codacy-coverage-reporter/7.1.0/codacy-coverage-reporter-7.1.0-assembly.jar
|
||||
$JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter.jar report -l Java -r main/commons/target/site/jacoco/jacoco.xml --partial
|
||||
$JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter.jar report -l Java -r main/ui/target/site/jacoco/jacoco.xml --partial
|
||||
$JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter.jar report -l Java -r main/launcher/target/site/jacoco/jacoco.xml --partial
|
||||
$JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter.jar final
|
||||
$JAVA_HOME/bin/java --illegal-access=permit -jar ~/codacy-coverage-reporter.jar report -l Java -r main/commons/target/site/jacoco/jacoco.xml --partial
|
||||
$JAVA_HOME/bin/java --illegal-access=permit -jar ~/codacy-coverage-reporter.jar report -l Java -r main/ui/target/site/jacoco/jacoco.xml --partial
|
||||
$JAVA_HOME/bin/java --illegal-access=permit -jar ~/codacy-coverage-reporter.jar report -l Java -r main/launcher/target/site/jacoco/jacoco.xml --partial
|
||||
$JAVA_HOME/bin/java --illegal-access=permit -jar ~/codacy-coverage-reporter.jar final
|
||||
env:
|
||||
CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }}
|
||||
- name: Assemble buildkit-linux.zip
|
||||
@@ -59,7 +60,7 @@ jobs:
|
||||
name: Draft a Release on GitHub Releases
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
if: startsWith(github.ref, 'refs/tags/') && github.repository == 'cryptomator/cryptomator'
|
||||
steps:
|
||||
- name: Download buildkit-linux.zip
|
||||
uses: actions/download-artifact@v1
|
||||
@@ -86,6 +87,11 @@ jobs:
|
||||
release_name: ${{ github.ref }}
|
||||
body: |
|
||||
:construction: Work in Progress
|
||||
|
||||
TODO:
|
||||
* [ ] add Linux appimage, zsync file and signature file
|
||||
* [ ] add Windows installer and signature file
|
||||
* [ ] add MacOs disk image and signature file
|
||||
draft: true
|
||||
prerelease: false
|
||||
- name: Upload buildkit-linux.zip to GitHub Releases
|
||||
|
||||
@@ -6,20 +6,32 @@ on:
|
||||
|
||||
jobs:
|
||||
closeTemplateViolation:
|
||||
name: Close bug reports that violate the issue template
|
||||
name: Validate bug report against issue template
|
||||
runs-on: ubuntu-latest
|
||||
if: contains(github.event.issue.labels.*.name, 'type:bug')
|
||||
steps:
|
||||
- if: |
|
||||
contains(github.event.issue.labels.*.name, 'type:bug')
|
||||
&& (
|
||||
!contains(github.event.issue.body, '<!-- oooooo -->')
|
||||
|| !contains(github.event.issue.body, '### Description')
|
||||
)
|
||||
name: Close Issue
|
||||
- name: Check "Description"
|
||||
if: |
|
||||
!contains(github.event.issue.body, env.MUST_CONTAIN)
|
||||
|| contains(toJson(github.event.issue.body), env.MUST_NOT_CONTAIN)
|
||||
run: exit 1
|
||||
env:
|
||||
MUST_CONTAIN: '### Description'
|
||||
MUST_NOT_CONTAIN: '### Description\r\n\r\n[Summarize your problem.]\r\n\r\n### System Setup'
|
||||
- name: Check "Steps to Reproduce"
|
||||
if: |
|
||||
!contains(github.event.issue.body, env.MUST_CONTAIN)
|
||||
|| contains(toJson(github.event.issue.body), env.MUST_NOT_CONTAIN)
|
||||
run: exit 1
|
||||
env:
|
||||
MUST_CONTAIN: '### Steps to Reproduce'
|
||||
MUST_NOT_CONTAIN: '### Steps to Reproduce\r\n\r\n1. [First step]\r\n2. [Second step]\r\n3. [and so on…]\r\n\r\n#### Expected Behavior'
|
||||
- name: Close issue if one of the checks failed
|
||||
if: ${{ failure() }}
|
||||
uses: peter-evans/close-issue@v1
|
||||
with:
|
||||
comment: |
|
||||
This bug report did ignore our issue template. 😞
|
||||
Auto-closing this issue, since it is most likely not useful.
|
||||
|
||||
_This decision was made by a bot. If you think the bot is wrong, let us know and we'll reopen this issue._
|
||||
_This decision was made by a bot. If you think the bot is wrong, let us know and we'll reopen this issue._
|
||||
|
||||
Generated
+1
-1
@@ -8,7 +8,7 @@
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_14" default="false" project-jdk-name="14" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_16" project-jdk-name="16" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="Cryptomator Linux" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="launcher" />
|
||||
<option name="VM_PARAMETERS" value="-Djdk.gtk.version=2 -Duser.language=en -Dcryptomator.settingsPath="~/.config/Cryptomator/settings.json" -Dcryptomator.ipcPortPath="~/.config/Cryptomator/ipcPort.bin" -Dcryptomator.logDir="~/.local/share/Cryptomator/logs" -Dcryptomator.mountPointsDir="~/.local/share/Cryptomator/mnt" -Xss20m -Xmx512m" />
|
||||
<option name="VM_PARAMETERS" value="-Djdk.gtk.version=2 -Duser.language=en -Dcryptomator.settingsPath="~/.config/Cryptomator/settings.json" -Dcryptomator.ipcPortPath="~/.config/Cryptomator/ipcPort.bin" -Dcryptomator.logDir="~/.local/share/Cryptomator/logs" -Dcryptomator.mountPointsDir="~/.local/share/Cryptomator/mnt" -Dcryptomator.showTrayIcon=true -Xss20m -Xmx512m" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="Cryptomator Linux Dev" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="launcher" />
|
||||
<option name="VM_PARAMETERS" value="-Djdk.gtk.version=2 -Duser.language=en -Dcryptomator.settingsPath="~/.config/Cryptomator-Dev/settings.json" -Dcryptomator.ipcPortPath="~/.config/Cryptomator-Dev/ipcPort.bin" -Dcryptomator.logDir="~/.local/share/Cryptomator-Dev/logs" -Dcryptomator.mountPointsDir="~/.local/share/Cryptomator-Dev/mnt" -Dfuse.experimental="true" -Xss20m -Xmx512m" />
|
||||
<option name="VM_PARAMETERS" value="-Djdk.gtk.version=2 -Duser.language=en -Dcryptomator.settingsPath="~/.config/Cryptomator-Dev/settings.json" -Dcryptomator.ipcPortPath="~/.config/Cryptomator-Dev/ipcPort.bin" -Dcryptomator.logDir="~/.local/share/Cryptomator-Dev/logs" -Dcryptomator.mountPointsDir="~/.local/share/Cryptomator-Dev/mnt" -Dcryptomator.showTrayIcon=true -Dfuse.experimental="true" -Xss20m -Xmx512m" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="Cryptomator Windows" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="launcher" />
|
||||
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath="~/AppData/Roaming/Cryptomator/settings.json" -Dcryptomator.ipcPortPath="~/AppData/Roaming/Cryptomator/ipcPort.bin" -Dcryptomator.logDir="~/AppData/Roaming/Cryptomator" -Dcryptomator.keychainPath="~/AppData/Roaming/Cryptomator/keychain.json" -Dcryptomator.mountPointsDir="~/Cryptomator" -Xss2m -Xmx512m" />
|
||||
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath="~/AppData/Roaming/Cryptomator/settings.json" -Dcryptomator.ipcPortPath="~/AppData/Roaming/Cryptomator/ipcPort.bin" -Dcryptomator.logDir="~/AppData/Roaming/Cryptomator" -Dcryptomator.keychainPath="~/AppData/Roaming/Cryptomator/keychain.json" -Dcryptomator.mountPointsDir="~/Cryptomator" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="Cryptomator Windows Dev" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="launcher" />
|
||||
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath="~/AppData/Roaming/Cryptomator-Dev/settings.json" -Dcryptomator.ipcPortPath="~/AppData/Roaming/Cryptomator-Dev/ipcPort.bin" -Dcryptomator.logDir="~/AppData/Roaming/Cryptomator-Dev" -Dcryptomator.keychainPath="~/AppData/Roaming/Cryptomator-Dev/keychain.json" -Dcryptomator.mountPointsDir="~/Cryptomator-Dev" -Dfuse.experimental="true" -Xss2m -Xmx512m" />
|
||||
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath="~/AppData/Roaming/Cryptomator-Dev/settings.json" -Dcryptomator.ipcPortPath="~/AppData/Roaming/Cryptomator-Dev/ipcPort.bin" -Dcryptomator.logDir="~/AppData/Roaming/Cryptomator-Dev" -Dcryptomator.keychainPath="~/AppData/Roaming/Cryptomator-Dev/keychain.json" -Dcryptomator.mountPointsDir="~/Cryptomator-Dev" -Dfuse.experimental="true" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
</envs>
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="launcher" />
|
||||
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath="~/Library/Application Support/Cryptomator/settings.json" -Dcryptomator.ipcPortPath="~/Library/Application Support/Cryptomator/ipcPort.bin" -Dcryptomator.logDir="~/Library/Logs/Cryptomator" -Xss2m -Xmx512m -ea" />
|
||||
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath="~/Library/Application Support/Cryptomator/settings.json" -Dcryptomator.ipcPortPath="~/Library/Application Support/Cryptomator/ipcPort.bin" -Dcryptomator.logDir="~/Library/Logs/Cryptomator" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m -ea" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
</envs>
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="launcher" />
|
||||
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath="~/Library/Application Support/Cryptomator-Dev/settings.json" -Dcryptomator.ipcPortPath="~/Library/Application Support/Cryptomator-Dev/ipcPort.bin" -Dcryptomator.logDir="~/Library/Logs/Cryptomator-Dev" -Xss2m -Xmx512m -ea" />
|
||||
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath="~/Library/Application Support/Cryptomator-Dev/settings.json" -Dcryptomator.ipcPortPath="~/Library/Application Support/Cryptomator-Dev/ipcPort.bin" -Dcryptomator.logDir="~/Library/Logs/Cryptomator-Dev" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m -ea" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[](https://github.com/cryptomator/cryptomator/actions?query=workflow%3ABuild)
|
||||
[](https://snyk.io/test/github/cryptomator/cryptomator?targetFile=main%2Fpom.xml)
|
||||
[](https://www.codacy.com/app/cryptomator/cryptomator?utm_source=github.com&utm_medium=referral&utm_content=cryptomator/cryptomator&utm_campaign=Badge_Grade)
|
||||
[](https://www.codacy.com/gh/cryptomator/cryptomator/dashboard)
|
||||
[](http://twitter.com/Cryptomator)
|
||||
[](https://translate.cryptomator.org/)
|
||||
[](https://github.com/cryptomator/cryptomator/releases/latest)
|
||||
@@ -17,11 +17,26 @@ Cryptomator is provided free of charge as an open-source project despite the hig
|
||||
|
||||
### Gold Sponsors
|
||||
|
||||
[<img src="https://cryptomator.org/img/sponsors/geewhiz.svg" alt="gee-whiz" height="96">](https://www.gee-whiz.de/)
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a href="https://www.gee-whiz.de/"><img src="https://cryptomator.org/img/sponsors/geewhiz.svg" alt="gee-whiz" height="80"></a></td>
|
||||
<td><a href="https://proxy-hub.com/"><img src="https://cryptomator.org/img/sponsors/proxyhub.svg" alt="Proxy-Hub" height="80"></a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Silver Sponsors
|
||||
|
||||
[](https://thebestvpn.com/)
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a href="https://thebestvpn.com/"><img src="https://cryptomator.org/img/sponsors/thebestvpn@2x.png" alt="TheBestVPN" height="64"></a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
- [Jameson Lopp](https://www.lopp.net/)
|
||||
|
||||
---
|
||||
|
||||
@@ -65,7 +80,7 @@ For more information on the security details visit [cryptomator.org](https://doc
|
||||
|
||||
### Dependencies
|
||||
|
||||
* JDK 14 (e.g. adoptopenjdk)
|
||||
* JDK 16 (e.g. adoptopenjdk)
|
||||
* Maven 3
|
||||
* Optional: OS-dependent build tools for native packaging (see [Windows](https://github.com/cryptomator/cryptomator-win), [OS X](https://github.com/cryptomator/cryptomator-osx), [Linux](https://github.com/cryptomator/builder-containers))
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>main</artifactId>
|
||||
<version>1.5.11</version>
|
||||
<version>1.6.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>buildkit</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>main</artifactId>
|
||||
<version>1.5.11</version>
|
||||
<version>1.6.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>commons</artifactId>
|
||||
<name>Cryptomator Commons</name>
|
||||
|
||||
@@ -47,10 +47,12 @@ public abstract class CommonsModule {
|
||||
@Named("licensePublicKey")
|
||||
static String provideLicensePublicKey() {
|
||||
// in PEM format without the dash-escaped begin/end lines
|
||||
return "MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQB7NfnqiZbg2KTmoflmZ71PbXru7oW" //
|
||||
+ "fmnV2yv3eDjlDfGruBrqz9TtXBZV/eYWt31xu1osIqaT12lKBvZ511aaAkIBeOEV" //
|
||||
+ "gwcBIlJr6kUw7NKzeJt7r2rrsOyQoOG2nWc/Of/NBqA3mIZRHk5Aq1YupFdD26QE" //
|
||||
+ "r0DzRyj4ixPIt38CQB8=";
|
||||
return """
|
||||
MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQB7NfnqiZbg2KTmoflmZ71PbXru7oW\
|
||||
fmnV2yv3eDjlDfGruBrqz9TtXBZV/eYWt31xu1osIqaT12lKBvZ511aaAkIBeOEV\
|
||||
gwcBIlJr6kUw7NKzeJt7r2rrsOyQoOG2nWc/Of/NBqA3mIZRHk5Aq1YupFdD26QE\
|
||||
r0DzRyj4ixPIt38CQB8=\
|
||||
""";
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
||||
@@ -21,14 +21,13 @@ import java.util.stream.StreamSupport;
|
||||
public class Environment {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Environment.class);
|
||||
private static final String USER_HOME = System.getProperty("user.home");
|
||||
private static final Path RELATIVE_HOME_DIR = Paths.get("~");
|
||||
private static final Path ABSOLUTE_HOME_DIR = Paths.get(USER_HOME);
|
||||
private static final char PATH_LIST_SEP = ':';
|
||||
private static final int DEFAULT_MIN_PW_LENGTH = 8;
|
||||
|
||||
@Inject
|
||||
public Environment() {
|
||||
LOG.debug("user.home: {}", System.getProperty("user.home"));
|
||||
LOG.debug("java.library.path: {}", System.getProperty("java.library.path"));
|
||||
LOG.debug("user.language: {}", System.getProperty("user.language"));
|
||||
LOG.debug("user.region: {}", System.getProperty("user.region"));
|
||||
@@ -40,6 +39,7 @@ public class Environment {
|
||||
LOG.debug("cryptomator.mountPointsDir: {}", System.getProperty("cryptomator.mountPointsDir"));
|
||||
LOG.debug("cryptomator.minPwLength: {}", System.getProperty("cryptomator.minPwLength"));
|
||||
LOG.debug("cryptomator.buildNumber: {}", System.getProperty("cryptomator.buildNumber"));
|
||||
LOG.debug("cryptomator.showTrayIcon: {}", System.getProperty("cryptomator.showTrayIcon"));
|
||||
LOG.debug("fuse.experimental: {}", Boolean.getBoolean("fuse.experimental"));
|
||||
}
|
||||
|
||||
@@ -75,6 +75,11 @@ public class Environment {
|
||||
return getInt("cryptomator.minPwLength", DEFAULT_MIN_PW_LENGTH);
|
||||
}
|
||||
|
||||
public boolean showTrayIcon() {
|
||||
return Boolean.getBoolean("cryptomator.showTrayIcon");
|
||||
}
|
||||
|
||||
@Deprecated // TODO: remove as soon as custom mount path works properly on Win+Fuse
|
||||
public boolean useExperimentalFuse() {
|
||||
return Boolean.getBoolean("fuse.experimental");
|
||||
}
|
||||
@@ -92,8 +97,13 @@ public class Environment {
|
||||
String value = System.getProperty(propertyName);
|
||||
return Optional.ofNullable(value).map(Paths::get);
|
||||
}
|
||||
// visible for testing
|
||||
|
||||
// visible for testing
|
||||
Path getHomeDir() {
|
||||
return getPath("user.home").orElseThrow();
|
||||
}
|
||||
|
||||
// visible for testing
|
||||
Stream<Path> getPaths(String propertyName) {
|
||||
Stream<String> rawSettingsPaths = getRawList(propertyName, PATH_LIST_SEP);
|
||||
return rawSettingsPaths.filter(Predicate.not(Strings::isNullOrEmpty)).map(Paths::get).map(this::replaceHomeDir);
|
||||
@@ -101,7 +111,7 @@ public class Environment {
|
||||
|
||||
private Path replaceHomeDir(Path path) {
|
||||
if (path.startsWith(RELATIVE_HOME_DIR)) {
|
||||
return ABSOLUTE_HOME_DIR.resolve(RELATIVE_HOME_DIR.relativize(path));
|
||||
return getHomeDir().resolve(RELATIVE_HOME_DIR.relativize(path));
|
||||
} else {
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@ class LicenseChecker {
|
||||
try {
|
||||
byte[] keyBytes = BaseEncoding.base64().decode(pemEncodedPublicKey);
|
||||
PublicKey key = KeyFactory.getInstance("EC").generatePublic(new X509EncodedKeySpec(keyBytes));
|
||||
if (key instanceof ECPublicKey) {
|
||||
return (ECPublicKey) key;
|
||||
if (key instanceof ECPublicKey k) {
|
||||
return k;
|
||||
} else {
|
||||
throw new IllegalStateException("Key not an EC public key.");
|
||||
}
|
||||
|
||||
@@ -68,6 +68,11 @@ public class KeychainManager implements KeychainAccessProvider {
|
||||
return keychain.getValue() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLocked() {
|
||||
return keychain.getValue() == null || keychain.get().isLocked();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the keychain knows a passphrase for the given key.
|
||||
* <p>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
package org.cryptomator.common.settings;
|
||||
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.Environment;
|
||||
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
@@ -39,7 +40,8 @@ public class Settings {
|
||||
public static final UiTheme DEFAULT_THEME = UiTheme.LIGHT;
|
||||
public static final KeychainBackend DEFAULT_KEYCHAIN_BACKEND = SystemUtils.IS_OS_WINDOWS ? KeychainBackend.WIN_SYSTEM_KEYCHAIN : SystemUtils.IS_OS_MAC ? KeychainBackend.MAC_SYSTEM_KEYCHAIN : KeychainBackend.GNOME;
|
||||
public static final NodeOrientation DEFAULT_USER_INTERFACE_ORIENTATION = NodeOrientation.LEFT_TO_RIGHT;
|
||||
private static final String DEFAULT_LICENSE_KEY = "";
|
||||
public static final String DEFAULT_LICENSE_KEY = "";
|
||||
public static final boolean DEFAULT_SHOW_MINIMIZE_BUTTON = false;
|
||||
|
||||
private final ObservableList<VaultSettings> directories = FXCollections.observableArrayList(VaultSettings::observables);
|
||||
private final BooleanProperty askedForUpdateCheck = new SimpleBooleanProperty(DEFAULT_ASKED_FOR_UPDATE_CHECK);
|
||||
@@ -54,13 +56,17 @@ public class Settings {
|
||||
private final ObjectProperty<KeychainBackend> keychainBackend = new SimpleObjectProperty<>(DEFAULT_KEYCHAIN_BACKEND);
|
||||
private final ObjectProperty<NodeOrientation> userInterfaceOrientation = new SimpleObjectProperty<>(DEFAULT_USER_INTERFACE_ORIENTATION);
|
||||
private final StringProperty licenseKey = new SimpleStringProperty(DEFAULT_LICENSE_KEY);
|
||||
private final BooleanProperty showMinimizeButton = new SimpleBooleanProperty(DEFAULT_SHOW_MINIMIZE_BUTTON);
|
||||
private final BooleanProperty showTrayIcon;
|
||||
|
||||
private Consumer<Settings> saveCmd;
|
||||
|
||||
/**
|
||||
* Package-private constructor; use {@link SettingsProvider}.
|
||||
*/
|
||||
Settings() {
|
||||
Settings(Environment env) {
|
||||
this.showTrayIcon = new SimpleBooleanProperty(env.showTrayIcon());
|
||||
|
||||
directories.addListener(this::somethingChanged);
|
||||
askedForUpdateCheck.addListener(this::somethingChanged);
|
||||
checkForUpdates.addListener(this::somethingChanged);
|
||||
@@ -74,6 +80,8 @@ public class Settings {
|
||||
keychainBackend.addListener(this::somethingChanged);
|
||||
userInterfaceOrientation.addListener(this::somethingChanged);
|
||||
licenseKey.addListener(this::somethingChanged);
|
||||
showMinimizeButton.addListener(this::somethingChanged);
|
||||
showTrayIcon.addListener(this::somethingChanged);
|
||||
}
|
||||
|
||||
void setSaveCmd(Consumer<Settings> saveCmd) {
|
||||
@@ -141,4 +149,12 @@ public class Settings {
|
||||
public StringProperty licenseKey() {
|
||||
return licenseKey;
|
||||
}
|
||||
|
||||
public BooleanProperty showMinimizeButton() {
|
||||
return showMinimizeButton;
|
||||
}
|
||||
|
||||
public BooleanProperty showTrayIcon() {
|
||||
return showTrayIcon;
|
||||
}
|
||||
}
|
||||
|
||||
+15
-2
@@ -9,19 +9,29 @@ import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javafx.geometry.NodeOrientation;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Singleton
|
||||
public class SettingsJsonAdapter extends TypeAdapter<Settings> {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SettingsJsonAdapter.class);
|
||||
|
||||
private final VaultSettingsJsonAdapter vaultSettingsJsonAdapter = new VaultSettingsJsonAdapter();
|
||||
private final Environment env;
|
||||
|
||||
@Inject
|
||||
public SettingsJsonAdapter(Environment env) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter out, Settings value) throws IOException {
|
||||
@@ -40,6 +50,8 @@ public class SettingsJsonAdapter extends TypeAdapter<Settings> {
|
||||
out.name("uiOrientation").value(value.userInterfaceOrientation().get().name());
|
||||
out.name("keychainBackend").value(value.keychainBackend().get().name());
|
||||
out.name("licenseKey").value(value.licenseKey().get());
|
||||
out.name("showMinimizeButton").value(value.showMinimizeButton().get());
|
||||
out.name("showTrayIcon").value(value.showTrayIcon().get());
|
||||
out.endObject();
|
||||
}
|
||||
|
||||
@@ -53,7 +65,7 @@ public class SettingsJsonAdapter extends TypeAdapter<Settings> {
|
||||
|
||||
@Override
|
||||
public Settings read(JsonReader in) throws IOException {
|
||||
Settings settings = new Settings();
|
||||
Settings settings = new Settings(env);
|
||||
|
||||
in.beginObject();
|
||||
while (in.hasNext()) {
|
||||
@@ -72,6 +84,8 @@ public class SettingsJsonAdapter extends TypeAdapter<Settings> {
|
||||
case "uiOrientation" -> settings.userInterfaceOrientation().set(parseUiOrientation(in.nextString()));
|
||||
case "keychainBackend" -> settings.keychainBackend().set(parseKeychainBackend(in.nextString()));
|
||||
case "licenseKey" -> settings.licenseKey().set(in.nextString());
|
||||
case "showMinimizeButton" -> settings.showMinimizeButton().set(in.nextBoolean());
|
||||
case "showTrayIcon" -> settings.showTrayIcon().set(in.nextBoolean());
|
||||
default -> {
|
||||
LOG.warn("Unsupported vault setting found in JSON: " + name);
|
||||
in.skipValue();
|
||||
@@ -137,5 +151,4 @@ public class SettingsJsonAdapter extends TypeAdapter<Settings> {
|
||||
in.endArray();
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -49,13 +49,14 @@ public class SettingsProvider implements Supplier<Settings> {
|
||||
|
||||
private final AtomicReference<ScheduledFuture<?>> scheduledSaveCmd = new AtomicReference<>();
|
||||
private final Supplier<Settings> settings = Suppliers.memoize(this::load);
|
||||
private final SettingsJsonAdapter settingsJsonAdapter = new SettingsJsonAdapter();
|
||||
private final SettingsJsonAdapter settingsJsonAdapter;
|
||||
private final Environment env;
|
||||
private final ScheduledExecutorService scheduler;
|
||||
private final Gson gson;
|
||||
|
||||
@Inject
|
||||
public SettingsProvider(Environment env, ScheduledExecutorService scheduler) {
|
||||
public SettingsProvider(SettingsJsonAdapter settingsJsonAdapter, Environment env, ScheduledExecutorService scheduler) {
|
||||
this.settingsJsonAdapter = settingsJsonAdapter;
|
||||
this.env = env;
|
||||
this.scheduler = scheduler;
|
||||
this.gson = new GsonBuilder() //
|
||||
@@ -70,7 +71,7 @@ public class SettingsProvider implements Supplier<Settings> {
|
||||
}
|
||||
|
||||
private Settings load() {
|
||||
Settings settings = env.getSettingsPath().flatMap(this::tryLoad).findFirst().orElse(new Settings());
|
||||
Settings settings = env.getSettingsPath().flatMap(this::tryLoad).findFirst().orElse(new Settings(env));
|
||||
settings.setSaveCmd(this::scheduleSave);
|
||||
return settings;
|
||||
}
|
||||
@@ -90,7 +91,7 @@ public class SettingsProvider implements Supplier<Settings> {
|
||||
}
|
||||
} catch (NoSuchFileException e) {
|
||||
return Stream.empty();
|
||||
} catch (IOException e) {
|
||||
} catch (IOException | JsonParseException e) {
|
||||
LOG.warn("Exception while loading settings from " + path, e);
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ public enum UiTheme {
|
||||
AUTOMATIC("preferences.general.theme.automatic");
|
||||
|
||||
public static UiTheme[] applicableValues() {
|
||||
if (SystemUtils.IS_OS_MAC) {
|
||||
if (SystemUtils.IS_OS_MAC || SystemUtils.IS_OS_WINDOWS) {
|
||||
return values();
|
||||
} else {
|
||||
return new UiTheme[]{LIGHT, DARK};
|
||||
|
||||
@@ -173,8 +173,7 @@ public class VaultSettings {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof VaultSettings && obj.getClass().equals(this.getClass())) {
|
||||
VaultSettings other = (VaultSettings) obj;
|
||||
if (obj instanceof VaultSettings other && obj.getClass().equals(this.getClass())) {
|
||||
return Objects.equals(this.id, other.id);
|
||||
} else {
|
||||
return false;
|
||||
|
||||
@@ -52,10 +52,11 @@ public class DokanyVolume extends AbstractVolume {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reveal() throws VolumeException {
|
||||
boolean success = mount.reveal();
|
||||
if (!success) {
|
||||
throw new VolumeException("Reveal failed.");
|
||||
public void reveal(Revealer revealer) throws VolumeException {
|
||||
try {
|
||||
mount.reveal(revealer::reveal);
|
||||
} catch (Exception e) {
|
||||
throw new VolumeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +80,7 @@ public class DokanyVolume extends AbstractVolume {
|
||||
public boolean supportsForcedUnmount() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
return DokanyVolume.isSupportedStatic();
|
||||
|
||||
@@ -20,7 +20,6 @@ import javax.inject.Named;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.SortedSet;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class FuseVolume extends AbstractVolume {
|
||||
@@ -73,11 +72,10 @@ public class FuseVolume extends AbstractVolume {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reveal() throws VolumeException {
|
||||
public void reveal(Revealer revealer) throws VolumeException {
|
||||
try {
|
||||
mount.revealInFileManager();
|
||||
} catch (CommandFailedException e) {
|
||||
LOG.debug("Revealing the vault in file manger failed: " + e.getMessage());
|
||||
mount.reveal(revealer::reveal);
|
||||
} catch (Exception e) {
|
||||
throw new VolumeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ public class Vault {
|
||||
if (vaultSettings.usesReadOnlyMode().get()) {
|
||||
flags.add(FileSystemFlags.READONLY);
|
||||
}
|
||||
if (vaultSettings.filenameLengthLimit().get() == -1) {
|
||||
if (!flags.contains(FileSystemFlags.READONLY) && vaultSettings.filenameLengthLimit().get() == -1) {
|
||||
LOG.debug("Determining file name length limitations...");
|
||||
int limit = new FileSystemCapabilityChecker().determineSupportedFileNameLength(getPath());
|
||||
vaultSettings.filenameLengthLimit().set(limit);
|
||||
@@ -121,12 +121,29 @@ public class Vault {
|
||||
return CryptoFileSystemProvider.newFileSystem(getPath(), fsProps);
|
||||
}
|
||||
|
||||
private void destroyCryptoFileSystem() {
|
||||
LOG.trace("Trying to close associated CryptoFS...");
|
||||
CryptoFileSystem fs = cryptoFileSystem.getAndSet(null);
|
||||
if (fs != null) {
|
||||
try {
|
||||
fs.close();
|
||||
} catch (IOException e) {
|
||||
LOG.error("Error closing file system.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void unlock(CharSequence passphrase) throws CryptoException, IOException, VolumeException, InvalidMountPointException {
|
||||
if (cryptoFileSystem.get() == null) {
|
||||
CryptoFileSystem fs = createCryptoFileSystem(passphrase);
|
||||
cryptoFileSystem.set(fs);
|
||||
volume = volumeProvider.get();
|
||||
volume.mount(fs, getEffectiveMountFlags());
|
||||
try {
|
||||
volume = volumeProvider.get();
|
||||
volume.mount(fs, getEffectiveMountFlags());
|
||||
} catch (Exception e) {
|
||||
destroyCryptoFileSystem();
|
||||
throw e;
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException("Already unlocked.");
|
||||
}
|
||||
@@ -138,18 +155,11 @@ public class Vault {
|
||||
} else {
|
||||
volume.unmount();
|
||||
}
|
||||
CryptoFileSystem fs = cryptoFileSystem.getAndSet(null);
|
||||
if (fs != null) {
|
||||
try {
|
||||
fs.close();
|
||||
} catch (IOException e) {
|
||||
LOG.error("Error closing file system.", e);
|
||||
}
|
||||
}
|
||||
destroyCryptoFileSystem();
|
||||
}
|
||||
|
||||
public void reveal() throws VolumeException {
|
||||
volume.reveal();
|
||||
public void reveal(Volume.Revealer vaultRevealer) throws VolumeException {
|
||||
volume.reveal(vaultRevealer);
|
||||
}
|
||||
|
||||
// ******************************************************************************
|
||||
@@ -345,8 +355,7 @@ public class Vault {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof Vault && obj.getClass().equals(this.getClass())) {
|
||||
final Vault other = (Vault) obj;
|
||||
if (obj instanceof Vault other && obj.getClass().equals(this.getClass())) {
|
||||
return Objects.equals(this.vaultSettings, other.vaultSettings);
|
||||
} else {
|
||||
return false;
|
||||
|
||||
+2
-2
@@ -22,10 +22,10 @@ class VaultListChangeListener implements ListChangeListener<Vault> {
|
||||
public void onChanged(Change<? extends Vault> c) {
|
||||
while (c.next()) {
|
||||
if (c.wasAdded()) {
|
||||
List<VaultSettings> addedSettings = c.getAddedSubList().stream().map(Vault::getVaultSettings).collect(Collectors.toList());
|
||||
List<VaultSettings> addedSettings = c.getAddedSubList().stream().map(Vault::getVaultSettings).toList();
|
||||
vaultSettingsList.addAll(c.getFrom(), addedSettings);
|
||||
} else if (c.wasRemoved()) {
|
||||
List<VaultSettings> removedSettings = c.getRemoved().stream().map(Vault::getVaultSettings).collect(Collectors.toList());
|
||||
List<VaultSettings> removedSettings = c.getRemoved().stream().map(Vault::getVaultSettings).toList();
|
||||
vaultSettingsList.removeAll(removedSettings);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ public class VaultListManager {
|
||||
}
|
||||
|
||||
private void addAll(Collection<VaultSettings> vaultSettings) {
|
||||
Collection<Vault> vaults = vaultSettings.stream().map(this::create).collect(Collectors.toList());
|
||||
Collection<Vault> vaults = vaultSettings.stream().map(this::create).toList();
|
||||
vaultList.addAll(vaults);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,15 @@ public interface Volume {
|
||||
*/
|
||||
void mount(CryptoFileSystem fs, String mountFlags) throws IOException, VolumeException, InvalidMountPointException;
|
||||
|
||||
void reveal() throws VolumeException;
|
||||
/**
|
||||
* Reveals the mounted volume.
|
||||
* <p>
|
||||
* The given {@code revealer} might be used to do it, but not necessarily.
|
||||
*
|
||||
* @param revealer An object capable of revealing the location of the mounted vault to view the content (e.g. in the default file browser).
|
||||
* @throws VolumeException
|
||||
*/
|
||||
void reveal(Revealer revealer) throws VolumeException;
|
||||
|
||||
void unmount() throws VolumeException;
|
||||
|
||||
@@ -79,4 +87,14 @@ public interface Volume {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides and unifies the different Revealer implementations in the different nio-adapters.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
interface Revealer {
|
||||
|
||||
void reveal(Path p) throws VolumeException;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class WebDavVolume implements Volume {
|
||||
|
||||
@@ -25,21 +26,27 @@ public class WebDavVolume implements Volume {
|
||||
private final Provider<WebDavServer> serverProvider;
|
||||
private final VaultSettings vaultSettings;
|
||||
private final Settings settings;
|
||||
private final WindowsDriveLetters windowsDriveLetters;
|
||||
|
||||
private WebDavServer server;
|
||||
private WebDavServletController servlet;
|
||||
private Mounter.Mount mount;
|
||||
private Path mountPoint;
|
||||
|
||||
@Inject
|
||||
public WebDavVolume(Provider<WebDavServer> serverProvider, VaultSettings vaultSettings, Settings settings) {
|
||||
public WebDavVolume(Provider<WebDavServer> serverProvider, VaultSettings vaultSettings, Settings settings, WindowsDriveLetters windowsDriveLetters) {
|
||||
this.serverProvider = serverProvider;
|
||||
this.vaultSettings = vaultSettings;
|
||||
this.settings = settings;
|
||||
this.windowsDriveLetters = windowsDriveLetters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mount(CryptoFileSystem fs, String mountFlags) throws VolumeException {
|
||||
startServlet(fs);
|
||||
mountServlet();
|
||||
}
|
||||
|
||||
private void startServlet(CryptoFileSystem fs){
|
||||
if (server == null) {
|
||||
server = serverProvider.get();
|
||||
}
|
||||
@@ -50,32 +57,38 @@ public class WebDavVolume implements Volume {
|
||||
String urlConformMountName = acceptable.negate().collapseFrom(vaultSettings.mountName().get(), '_');
|
||||
servlet = server.createWebDavServlet(fs.getPath("/"), vaultSettings.getId() + "/" + urlConformMountName);
|
||||
servlet.start();
|
||||
mount();
|
||||
}
|
||||
|
||||
private void mount() throws VolumeException {
|
||||
private void mountServlet() throws VolumeException {
|
||||
if (servlet == null) {
|
||||
throw new IllegalStateException("Mounting requires unlocked WebDAV servlet.");
|
||||
}
|
||||
|
||||
//on windows, prevent an automatic drive letter selection in the upstream library. Either we choose already a specifc one or there is no free.
|
||||
Supplier<String> driveLetterSupplier;
|
||||
if(System.getProperty("os.name").toLowerCase().contains("windows") && vaultSettings.winDriveLetter().isEmpty().get()) {
|
||||
driveLetterSupplier = () -> windowsDriveLetters.getAvailableDriveLetter().orElse(null);
|
||||
} else {
|
||||
driveLetterSupplier = () -> vaultSettings.winDriveLetter().get();
|
||||
}
|
||||
|
||||
MountParams mountParams = MountParams.create() //
|
||||
.withWindowsDriveLetter(vaultSettings.winDriveLetter().get()) //
|
||||
.withWindowsDriveLetter(driveLetterSupplier.get()) //
|
||||
.withPreferredGvfsScheme(settings.preferredGvfsScheme().get().getPrefix())//
|
||||
.withWebdavHostname(getLocalhostAliasOrNull()) //
|
||||
.build();
|
||||
try {
|
||||
this.mount = servlet.mount(mountParams); // might block this thread for a while
|
||||
} catch (Mounter.CommandFailedException e) {
|
||||
e.printStackTrace();
|
||||
throw new VolumeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reveal() throws VolumeException {
|
||||
public void reveal(Revealer revealer) throws VolumeException {
|
||||
try {
|
||||
mount.reveal();
|
||||
} catch (Mounter.CommandFailedException e) {
|
||||
e.printStackTrace();
|
||||
mount.reveal(revealer::reveal);
|
||||
} catch (Exception e) {
|
||||
throw new VolumeException(e);
|
||||
}
|
||||
}
|
||||
@@ -102,7 +115,7 @@ public class WebDavVolume implements Volume {
|
||||
|
||||
@Override
|
||||
public Optional<Path> getMountPoint() {
|
||||
return Optional.ofNullable(mountPoint); //TODO
|
||||
return mount.getMountPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -8,6 +8,7 @@ import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
@@ -20,14 +21,10 @@ class EnvironmentTest {
|
||||
|
||||
private Environment env;
|
||||
|
||||
@BeforeAll
|
||||
static void init() {
|
||||
System.setProperty("user.home", "/home/testuser");
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void initEach() {
|
||||
env = new Environment();
|
||||
void init() {
|
||||
env = Mockito.spy(new Environment());
|
||||
Mockito.when(env.getHomeDir()).thenReturn(Path.of("/home/testuser"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -35,7 +32,7 @@ class EnvironmentTest {
|
||||
public void testSettingsPath() {
|
||||
System.setProperty("cryptomator.settingsPath", "~/.config/Cryptomator/settings.json:~/.Cryptomator/settings.json");
|
||||
|
||||
List<Path> result = env.getSettingsPath().collect(Collectors.toList());
|
||||
List<Path> result = env.getSettingsPath().toList();
|
||||
MatcherAssert.assertThat(result, Matchers.hasSize(2));
|
||||
MatcherAssert.assertThat(result, Matchers.contains(Paths.get("/home/testuser/.config/Cryptomator/settings.json"), //
|
||||
Paths.get("/home/testuser/.Cryptomator/settings.json")));
|
||||
@@ -46,7 +43,7 @@ class EnvironmentTest {
|
||||
public void testIpcPortPath() {
|
||||
System.setProperty("cryptomator.ipcPortPath", "~/.config/Cryptomator/ipcPort.bin:~/.Cryptomator/ipcPort.bin");
|
||||
|
||||
List<Path> result = env.getIpcPortPath().collect(Collectors.toList());
|
||||
List<Path> result = env.getIpcPortPath().toList();
|
||||
MatcherAssert.assertThat(result, Matchers.hasSize(2));
|
||||
MatcherAssert.assertThat(result, Matchers.contains(Paths.get("/home/testuser/.config/Cryptomator/ipcPort.bin"), //
|
||||
Paths.get("/home/testuser/.Cryptomator/ipcPort.bin")));
|
||||
@@ -57,7 +54,7 @@ class EnvironmentTest {
|
||||
public void testKeychainPath() {
|
||||
System.setProperty("cryptomator.keychainPath", "~/AppData/Roaming/Cryptomator/keychain.json");
|
||||
|
||||
List<Path> result = env.getKeychainPath().collect(Collectors.toList());
|
||||
List<Path> result = env.getKeychainPath().toList();
|
||||
MatcherAssert.assertThat(result, Matchers.hasSize(1));
|
||||
MatcherAssert.assertThat(result, Matchers.contains(Paths.get("/home/testuser/AppData/Roaming/Cryptomator/keychain.json")));
|
||||
}
|
||||
@@ -91,7 +88,7 @@ class EnvironmentTest {
|
||||
@DisplayName("test.path.property=")
|
||||
public void testEmptyList() {
|
||||
System.setProperty("test.path.property", "");
|
||||
List<Path> result = env.getPaths("test.path.property").collect(Collectors.toList());
|
||||
List<Path> result = env.getPaths("test.path.property").toList();
|
||||
|
||||
MatcherAssert.assertThat(result, Matchers.hasSize(0));
|
||||
}
|
||||
@@ -100,7 +97,7 @@ class EnvironmentTest {
|
||||
@DisplayName("test.path.property=/foo/bar/test")
|
||||
public void testSingleAbsolutePath() {
|
||||
System.setProperty("test.path.property", "/foo/bar/test");
|
||||
List<Path> result = env.getPaths("test.path.property").collect(Collectors.toList());
|
||||
List<Path> result = env.getPaths("test.path.property").toList();
|
||||
|
||||
MatcherAssert.assertThat(result, Matchers.hasSize(1));
|
||||
MatcherAssert.assertThat(result, Matchers.hasItem(Paths.get("/foo/bar/test")));
|
||||
@@ -110,7 +107,7 @@ class EnvironmentTest {
|
||||
@DisplayName("test.path.property=~/test")
|
||||
public void testSingleHomeRelativePath() {
|
||||
System.setProperty("test.path.property", "~/test");
|
||||
List<Path> result = env.getPaths("test.path.property").collect(Collectors.toList());
|
||||
List<Path> result = env.getPaths("test.path.property").toList();
|
||||
|
||||
MatcherAssert.assertThat(result, Matchers.hasSize(1));
|
||||
MatcherAssert.assertThat(result, Matchers.hasItem(Paths.get("/home/testuser/test")));
|
||||
@@ -120,7 +117,7 @@ class EnvironmentTest {
|
||||
@DisplayName("test.path.property=~/test:~/test2:/foo/bar/test")
|
||||
public void testMultiplePaths() {
|
||||
System.setProperty("test.path.property", "~/test:~/test2:/foo/bar/test");
|
||||
List<Path> result = env.getPaths("test.path.property").collect(Collectors.toList());
|
||||
List<Path> result = env.getPaths("test.path.property").toList();
|
||||
|
||||
MatcherAssert.assertThat(result, Matchers.hasSize(3));
|
||||
MatcherAssert.assertThat(result, Matchers.contains(Paths.get("/home/testuser/test"), //
|
||||
|
||||
@@ -9,10 +9,12 @@ import java.util.Optional;
|
||||
|
||||
class LicenseCheckerTest {
|
||||
|
||||
private static final String PUBLIC_KEY = "MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBgc4HZz+/fBbC7lmEww0AO3NK9wVZ" //
|
||||
+ "PDZ0VEnsaUFLEYpTzb90nITtJUcPUbvOsdZIZ1Q8fnbquAYgxXL5UgHMoywAib47" //
|
||||
+ "6MkyyYgPk0BXZq3mq4zImTRNuaU9slj9TVJ3ScT3L1bXwVuPJDzpr5GOFpaj+WwM" //
|
||||
+ "Al8G7CqwoJOsW7Kddns=";
|
||||
private static final String PUBLIC_KEY = """
|
||||
MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBgc4HZz+/fBbC7lmEww0AO3NK9wVZ\
|
||||
PDZ0VEnsaUFLEYpTzb90nITtJUcPUbvOsdZIZ1Q8fnbquAYgxXL5UgHMoywAib47\
|
||||
6MkyyYgPk0BXZq3mq4zImTRNuaU9slj9TVJ3ScT3L1bXwVuPJDzpr5GOFpaj+WwM\
|
||||
Al8G7CqwoJOsW7Kddns=\
|
||||
""";
|
||||
|
||||
private LicenseChecker licenseChecker;
|
||||
|
||||
|
||||
@@ -44,4 +44,9 @@ class MapKeychainAccess implements KeychainAccessProvider {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLocked() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+16
-8
@@ -5,26 +5,34 @@
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.common.settings;
|
||||
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class SettingsJsonAdapterTest {
|
||||
|
||||
private final SettingsJsonAdapter adapter = new SettingsJsonAdapter();
|
||||
private final Environment env = Mockito.mock(Environment.class);
|
||||
private final SettingsJsonAdapter adapter = new SettingsJsonAdapter(env);
|
||||
|
||||
@Test
|
||||
public void testDeserialize() throws IOException {
|
||||
String vault1Json = "{\"id\": \"1\", \"path\": \"/vault1\", \"mountName\": \"vault1\", \"winDriveLetter\": \"X\"}";
|
||||
String vault2Json = "{\"id\": \"2\", \"path\": \"/vault2\", \"mountName\": \"vault2\", \"winDriveLetter\": \"Y\"}";
|
||||
String json = "{\"directories\": [" + vault1Json + "," + vault2Json + "]," //
|
||||
+ "\"checkForUpdatesEnabled\": true,"//
|
||||
+ "\"port\": 8080,"//
|
||||
+ "\"numTrayNotifications\": 42,"//
|
||||
+ "\"preferredVolumeImpl\": \"FUSE\"}";
|
||||
String json = """
|
||||
{
|
||||
"directories": [
|
||||
{"id": "1", "path": "/vault1", "mountName": "vault1", "winDriveLetter": "X"},
|
||||
{"id": "2", "path": "/vault2", "mountName": "vault2", "winDriveLetter": "Y"}
|
||||
],
|
||||
"checkForUpdatesEnabled": true,
|
||||
"port": 8080,
|
||||
"numTrayNotifications": 42,
|
||||
"preferredVolumeImpl": "FUSE"
|
||||
}
|
||||
""";
|
||||
|
||||
Settings settings = adapter.fromJson(json);
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.common.settings;
|
||||
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
@@ -14,8 +15,10 @@ public class SettingsTest {
|
||||
|
||||
@Test
|
||||
public void testAutoSave() {
|
||||
Environment env = Mockito.mock(Environment.class);
|
||||
@SuppressWarnings("unchecked") Consumer<Settings> changeListener = Mockito.mock(Consumer.class);
|
||||
Settings settings = new Settings();
|
||||
|
||||
Settings settings = new Settings(env);
|
||||
settings.setSaveCmd(changeListener);
|
||||
VaultSettings vaultSettings = VaultSettings.withRandomId();
|
||||
Mockito.verify(changeListener, Mockito.times(0)).accept(settings);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>main</artifactId>
|
||||
<version>1.5.11</version>
|
||||
<version>1.6.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>launcher</artifactId>
|
||||
<name>Cryptomator Launcher</name>
|
||||
|
||||
@@ -41,7 +41,7 @@ class FileOpenRequestHandler {
|
||||
}
|
||||
|
||||
private void openFiles(OpenFilesEvent evt) {
|
||||
Collection<Path> pathsToOpen = evt.getFiles().stream().map(File::toPath).collect(Collectors.toList());
|
||||
Collection<Path> pathsToOpen = evt.getFiles().stream().map(File::toPath).toList();
|
||||
AppLaunchEvent launchEvent = new AppLaunchEvent(AppLaunchEvent.EventType.OPEN_FILE, pathsToOpen);
|
||||
tryToEnqueueFileOpenRequest(launchEvent);
|
||||
}
|
||||
@@ -59,7 +59,7 @@ class FileOpenRequestHandler {
|
||||
LOG.trace("Argument not a valid path: {}", str);
|
||||
return null;
|
||||
}
|
||||
}).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
}).filter(Objects::nonNull).toList();
|
||||
if (!pathsToOpen.isEmpty()) {
|
||||
AppLaunchEvent launchEvent = new AppLaunchEvent(AppLaunchEvent.EventType.OPEN_FILE, pathsToOpen);
|
||||
tryToEnqueueFileOpenRequest(launchEvent);
|
||||
|
||||
@@ -47,8 +47,8 @@ public class LoggerModule {
|
||||
@Singleton
|
||||
static LoggerContext provideLoggerContext() {
|
||||
ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory();
|
||||
if (loggerFactory instanceof LoggerContext) {
|
||||
return (LoggerContext) loggerFactory;
|
||||
if (loggerFactory instanceof LoggerContext context) {
|
||||
return context;
|
||||
} else {
|
||||
throw new IllegalStateException("SLF4J not bound to Logback.");
|
||||
}
|
||||
|
||||
+13
-26
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>main</artifactId>
|
||||
<version>1.5.11</version>
|
||||
<version>1.6.0-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Cryptomator</name>
|
||||
|
||||
@@ -22,24 +22,25 @@
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.jdk.version>16</project.jdk.version>
|
||||
|
||||
<!-- cryptomator dependencies -->
|
||||
<cryptomator.cryptofs.version>1.9.13</cryptomator.cryptofs.version>
|
||||
<cryptomator.integrations.version>0.1.6</cryptomator.integrations.version>
|
||||
<cryptomator.integrations.win.version>0.2.1</cryptomator.integrations.win.version>
|
||||
<cryptomator.integrations.mac.version>0.1.0-beta3</cryptomator.integrations.mac.version>
|
||||
<cryptomator.integrations.linux.version>0.1.0-beta2</cryptomator.integrations.linux.version>
|
||||
<cryptomator.fuse.version>1.2.6</cryptomator.fuse.version>
|
||||
<cryptomator.dokany.version>1.2.1</cryptomator.dokany.version>
|
||||
<cryptomator.webdav.version>1.0.14</cryptomator.webdav.version>
|
||||
<cryptomator.cryptofs.version>1.9.14</cryptomator.cryptofs.version>
|
||||
<cryptomator.integrations.version>1.0.0-beta2</cryptomator.integrations.version>
|
||||
<cryptomator.integrations.win.version>1.0.0-beta2</cryptomator.integrations.win.version>
|
||||
<cryptomator.integrations.mac.version>1.0.0-beta2</cryptomator.integrations.mac.version>
|
||||
<cryptomator.integrations.linux.version>1.0.0-beta1</cryptomator.integrations.linux.version>
|
||||
<cryptomator.fuse.version>1.2.9</cryptomator.fuse.version>
|
||||
<cryptomator.dokany.version>1.2.4</cryptomator.dokany.version>
|
||||
<cryptomator.webdav.version>1.1.4</cryptomator.webdav.version>
|
||||
|
||||
<!-- 3rd party dependencies -->
|
||||
<javafx.version>15</javafx.version>
|
||||
<commons-lang3.version>3.11</commons-lang3.version>
|
||||
<jwt.version>3.11.0</jwt.version>
|
||||
<jwt.version>3.12.0</jwt.version>
|
||||
<easybind.version>2.1.0</easybind.version>
|
||||
<guava.version>30.0-jre</guava.version>
|
||||
<dagger.version>2.29.1</dagger.version>
|
||||
<dagger.version>2.32</dagger.version>
|
||||
<gson.version>2.8.6</gson.version>
|
||||
<slf4j.version>1.7.30</slf4j.version>
|
||||
<logback.version>1.2.3</logback.version>
|
||||
@@ -50,13 +51,6 @@
|
||||
<hamcrest.version>2.2</hamcrest.version>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jcenter</id>
|
||||
<url>https://jcenter.bintray.com</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<!-- modules -->
|
||||
@@ -175,13 +169,6 @@
|
||||
<artifactId>java-jwt</artifactId>
|
||||
<version>${jwt.version}</version>
|
||||
</dependency>
|
||||
<!-- fixes CVE-2020-25649, can be removed once https://github.com/auth0/java-jwt/pull/463 is closed and released -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.10.5.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- EasyBind -->
|
||||
<dependency>
|
||||
@@ -444,7 +431,7 @@
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<release>14</release>
|
||||
<release>${project.jdk.version}</release>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>com.google.dagger</groupId>
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>main</artifactId>
|
||||
<version>1.5.11</version>
|
||||
<version>1.6.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>ui</artifactId>
|
||||
<name>Cryptomator GUI</name>
|
||||
|
||||
@@ -6,7 +6,7 @@ import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FXMLLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
@@ -43,8 +43,8 @@ public abstract class AddVaultModule {
|
||||
@Provides
|
||||
@AddVaultWizardWindow
|
||||
@AddVaultWizardScoped
|
||||
static FXMLLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FXMLLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -91,50 +91,50 @@ public abstract class AddVaultModule {
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.ADDVAULT_WELCOME)
|
||||
@AddVaultWizardScoped
|
||||
static Scene provideWelcomeScene(@AddVaultWizardWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.ADDVAULT_WELCOME.getRessourcePathString());
|
||||
static Scene provideWelcomeScene(@AddVaultWizardWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.ADDVAULT_WELCOME);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.ADDVAULT_EXISTING)
|
||||
@AddVaultWizardScoped
|
||||
static Scene provideChooseExistingVaultScene(@AddVaultWizardWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.ADDVAULT_EXISTING.getRessourcePathString());
|
||||
static Scene provideChooseExistingVaultScene(@AddVaultWizardWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.ADDVAULT_EXISTING);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.ADDVAULT_NEW_NAME)
|
||||
@AddVaultWizardScoped
|
||||
static Scene provideCreateNewVaultNameScene(@AddVaultWizardWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.ADDVAULT_NEW_NAME.getRessourcePathString());
|
||||
static Scene provideCreateNewVaultNameScene(@AddVaultWizardWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.ADDVAULT_NEW_NAME);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.ADDVAULT_NEW_LOCATION)
|
||||
@AddVaultWizardScoped
|
||||
static Scene provideCreateNewVaultLocationScene(@AddVaultWizardWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.ADDVAULT_NEW_LOCATION.getRessourcePathString());
|
||||
static Scene provideCreateNewVaultLocationScene(@AddVaultWizardWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.ADDVAULT_NEW_LOCATION);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.ADDVAULT_NEW_PASSWORD)
|
||||
@AddVaultWizardScoped
|
||||
static Scene provideCreateNewVaultPasswordScene(@AddVaultWizardWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.ADDVAULT_NEW_PASSWORD.getRessourcePathString());
|
||||
static Scene provideCreateNewVaultPasswordScene(@AddVaultWizardWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.ADDVAULT_NEW_PASSWORD);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.ADDVAULT_NEW_RECOVERYKEY)
|
||||
@AddVaultWizardScoped
|
||||
static Scene provideCreateNewVaultRecoveryKeyScene(@AddVaultWizardWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.ADDVAULT_NEW_RECOVERYKEY.getRessourcePathString());
|
||||
static Scene provideCreateNewVaultRecoveryKeyScene(@AddVaultWizardWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.ADDVAULT_NEW_RECOVERYKEY);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.ADDVAULT_SUCCESS)
|
||||
@AddVaultWizardScoped
|
||||
static Scene provideCreateNewVaultSuccessScene(@AddVaultWizardWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.ADDVAULT_SUCCESS.getRessourcePathString());
|
||||
static Scene provideCreateNewVaultSuccessScene(@AddVaultWizardWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.ADDVAULT_SUCCESS);
|
||||
}
|
||||
|
||||
// ------------------
|
||||
|
||||
@@ -5,7 +5,7 @@ import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FXMLLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
@@ -37,8 +37,8 @@ abstract class ChangePasswordModule {
|
||||
@Provides
|
||||
@ChangePasswordWindow
|
||||
@ChangePasswordScoped
|
||||
static FXMLLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FXMLLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -56,8 +56,8 @@ abstract class ChangePasswordModule {
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.CHANGEPASSWORD)
|
||||
@ChangePasswordScoped
|
||||
static Scene provideUnlockScene(@ChangePasswordWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/changepassword.fxml");
|
||||
static Scene provideUnlockScene(@ChangePasswordWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.CHANGEPASSWORD);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -42,8 +42,8 @@ public class DefaultSceneFactory implements Function<Parent, Scene> {
|
||||
protected void configureScene(Scene scene) {
|
||||
scene.windowProperty().addListener(observable -> {
|
||||
Window window = scene.getWindow();
|
||||
if (window instanceof Stage) {
|
||||
setupDefaultAccelerators(scene, (Stage) window);
|
||||
if (window instanceof Stage s) {
|
||||
setupDefaultAccelerators(scene, s);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ import java.util.ResourceBundle;
|
||||
abstract class ErrorModule {
|
||||
|
||||
@Provides
|
||||
static FXMLLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FXMLLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -38,8 +38,8 @@ abstract class ErrorModule {
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.ERROR)
|
||||
static Scene provideErrorScene(FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.ERROR.getRessourcePathString());
|
||||
static Scene provideErrorScene(FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.ERROR);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ public enum FxmlFile {
|
||||
this.ressourcePathString = ressourcePathString;
|
||||
}
|
||||
|
||||
public String getRessourcePathString() {
|
||||
String getRessourcePathString() {
|
||||
return ressourcePathString;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-3
@@ -11,13 +11,13 @@ import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class FXMLLoaderFactory {
|
||||
public class FxmlLoaderFactory {
|
||||
|
||||
private final Map<Class<? extends FxController>, Provider<FxController>> controllerFactories;
|
||||
private final Function<Parent, Scene> sceneFactory;
|
||||
private final ResourceBundle resourceBundle;
|
||||
|
||||
public FXMLLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> controllerFactories, Function<Parent, Scene> sceneFactory, ResourceBundle resourceBundle) {
|
||||
public FxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> controllerFactories, Function<Parent, Scene> sceneFactory, ResourceBundle resourceBundle) {
|
||||
this.controllerFactories = controllerFactories;
|
||||
this.sceneFactory = sceneFactory;
|
||||
this.resourceBundle = resourceBundle;
|
||||
@@ -48,13 +48,17 @@ public class FXMLLoaderFactory {
|
||||
return loader;
|
||||
}
|
||||
|
||||
public Scene createScene(FxmlFile fxmlFile) {
|
||||
return createScene(fxmlFile.getRessourcePathString());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link #load(String) Loads} the FXML file and creates a new Scene containing the loaded ui.
|
||||
*
|
||||
* @param fxmlResourceName Name of the resource (as in {@link Class#getResource(String)}).
|
||||
* @throws UncheckedIOException wrapping any IOException thrown by {@link #load(String)).
|
||||
*/
|
||||
public Scene createScene(String fxmlResourceName) {
|
||||
private Scene createScene(String fxmlResourceName) {
|
||||
final FXMLLoader loader;
|
||||
try {
|
||||
loader = load(fxmlResourceName);
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.cryptomator.ui.common;
|
||||
|
||||
import dagger.Lazy;
|
||||
import org.cryptomator.common.vaults.Volume;
|
||||
import org.cryptomator.ui.fxapp.FxApplicationScoped;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.application.Application;
|
||||
import java.nio.file.Path;
|
||||
|
||||
@FxApplicationScoped
|
||||
public class HostServiceRevealer implements Volume.Revealer {
|
||||
|
||||
private final Lazy<Application> application;
|
||||
|
||||
@Inject
|
||||
public HostServiceRevealer(Lazy<Application> application) {
|
||||
this.application = application;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reveal(Path p) throws Volume.VolumeException {
|
||||
application.get().getHostServices().showDocument(p.toUri().toString());
|
||||
}
|
||||
}
|
||||
@@ -23,10 +23,12 @@ public class VaultService {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(VaultService.class);
|
||||
|
||||
private final ExecutorService executorService;
|
||||
private final HostServiceRevealer vaultRevealer;
|
||||
|
||||
@Inject
|
||||
public VaultService(ExecutorService executorService) {
|
||||
public VaultService(ExecutorService executorService, HostServiceRevealer vaultRevealer) {
|
||||
this.executorService = executorService;
|
||||
this.vaultRevealer = vaultRevealer;
|
||||
}
|
||||
|
||||
public void reveal(Vault vault) {
|
||||
@@ -39,7 +41,7 @@ public class VaultService {
|
||||
* @param vault The vault to reveal
|
||||
*/
|
||||
public Task<Vault> createRevealTask(Vault vault) {
|
||||
Task<Vault> task = new RevealVaultTask(vault);
|
||||
Task<Vault> task = new RevealVaultTask(vault, vaultRevealer);
|
||||
task.setOnSucceeded(evt -> LOG.info("Revealed {}", vault.getDisplayName()));
|
||||
task.setOnFailed(evt -> LOG.error("Failed to reveal " + vault.getDisplayName(), evt.getSource().getException()));
|
||||
return task;
|
||||
@@ -99,19 +101,22 @@ public class VaultService {
|
||||
private static class RevealVaultTask extends Task<Vault> {
|
||||
|
||||
private final Vault vault;
|
||||
private final Volume.Revealer revealer;
|
||||
|
||||
/**
|
||||
* @param vault The vault to lock
|
||||
* @param revealer The object to use to show the vault content to the user.
|
||||
*/
|
||||
public RevealVaultTask(Vault vault) {
|
||||
public RevealVaultTask(Vault vault, Volume.Revealer revealer) {
|
||||
this.vault = vault;
|
||||
this.revealer = revealer;
|
||||
|
||||
setOnFailed(evt -> LOG.error("Failed to reveal " + vault.getDisplayName(), getException()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Vault call() throws Volume.VolumeException {
|
||||
vault.reveal();
|
||||
vault.reveal(revealer);
|
||||
return vault;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FXMLLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
@@ -29,8 +29,8 @@ abstract class ForgetPasswordModule {
|
||||
@Provides
|
||||
@ForgetPasswordWindow
|
||||
@ForgetPasswordScoped
|
||||
static FXMLLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FXMLLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -62,8 +62,8 @@ abstract class ForgetPasswordModule {
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.FORGET_PASSWORD)
|
||||
@ForgetPasswordScoped
|
||||
static Scene provideForgetPasswordScene(@ForgetPasswordWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/forget_password.fxml");
|
||||
static Scene provideForgetPasswordScene(@ForgetPasswordWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.FORGET_PASSWORD);
|
||||
}
|
||||
|
||||
// ------------------
|
||||
|
||||
@@ -32,6 +32,8 @@ import javafx.stage.Stage;
|
||||
import javafx.stage.Window;
|
||||
import java.awt.desktop.QuitResponse;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
@FxApplicationScoped
|
||||
public class FxApplication extends Application {
|
||||
@@ -84,7 +86,7 @@ public class FxApplication extends Application {
|
||||
}
|
||||
|
||||
private void hasVisibleStagesChanged(@SuppressWarnings("unused") ObservableValue<? extends Boolean> observableValue, @SuppressWarnings("unused") boolean oldValue, boolean newValue) {
|
||||
LOG.warn("has visible stages: {}", newValue);
|
||||
LOG.debug("has visible stages: {}", newValue);
|
||||
if (newValue) {
|
||||
trayIntegration.ifPresent(TrayIntegrationProvider::restoredFromTray);
|
||||
} else {
|
||||
@@ -99,11 +101,14 @@ public class FxApplication extends Application {
|
||||
});
|
||||
}
|
||||
|
||||
public void showMainWindow() {
|
||||
public CompletionStage<Stage> showMainWindow() {
|
||||
CompletableFuture<Stage> future = new CompletableFuture<>();
|
||||
Platform.runLater(() -> {
|
||||
mainWindow.get().showMainWindow();
|
||||
var win = mainWindow.get().showMainWindow();
|
||||
LOG.debug("Showing MainWindow");
|
||||
future.complete(win);
|
||||
});
|
||||
return future;
|
||||
}
|
||||
|
||||
public void startUnlockWorkflow(Vault vault, Optional<Stage> owner) {
|
||||
@@ -132,13 +137,13 @@ public class FxApplication extends Application {
|
||||
}
|
||||
|
||||
private void appThemeChanged(@SuppressWarnings("unused") ObservableValue<? extends UiTheme> observable, @SuppressWarnings("unused") UiTheme oldValue, UiTheme newValue) {
|
||||
appearanceProvider.ifPresent(appearanceProvider -> {
|
||||
if (appearanceProvider.isPresent() && oldValue == UiTheme.AUTOMATIC && newValue != UiTheme.AUTOMATIC) {
|
||||
try {
|
||||
appearanceProvider.removeListener(systemInterfaceThemeListener);
|
||||
appearanceProvider.get().removeListener(systemInterfaceThemeListener);
|
||||
} catch (UiAppearanceException e) {
|
||||
LOG.error("Failed to disable automatic theme switching.");
|
||||
}
|
||||
});
|
||||
}
|
||||
loadSelectedStyleSheet(newValue);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,11 +5,8 @@
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.ui.fxapp;
|
||||
|
||||
import dagger.BindsInstance;
|
||||
import dagger.Subcomponent;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
@FxApplicationScoped
|
||||
@Subcomponent(modules = FxApplicationModule.class)
|
||||
public interface FxApplicationComponent {
|
||||
@@ -19,9 +16,6 @@ public interface FxApplicationComponent {
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
|
||||
@BindsInstance
|
||||
Builder trayMenuSupported(@Named("trayMenuSupported") boolean trayMenuSupported);
|
||||
|
||||
FxApplicationComponent build();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.cryptomator.ui.launcher;
|
||||
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.common.vaults.VaultListManager;
|
||||
import org.cryptomator.ui.fxapp.FxApplication;
|
||||
import org.slf4j.Logger;
|
||||
@@ -34,15 +35,15 @@ class AppLaunchEventHandler {
|
||||
this.vaultListManager = vaultListManager;
|
||||
}
|
||||
|
||||
public void startHandlingLaunchEvents(boolean hasTrayIcon) {
|
||||
executorService.submit(() -> handleLaunchEvents(hasTrayIcon));
|
||||
public void startHandlingLaunchEvents() {
|
||||
executorService.submit(this::handleLaunchEvents);
|
||||
}
|
||||
|
||||
private void handleLaunchEvents(boolean hasTrayIcon) {
|
||||
private void handleLaunchEvents() {
|
||||
try {
|
||||
while (!Thread.interrupted()) {
|
||||
AppLaunchEvent event = launchEventQueue.take();
|
||||
handleLaunchEvent(hasTrayIcon, event);
|
||||
handleLaunchEvent(event);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
LOG.warn("Interrupted launch event handler.");
|
||||
@@ -50,12 +51,12 @@ class AppLaunchEventHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleLaunchEvent(boolean hasTrayIcon, AppLaunchEvent event) {
|
||||
private void handleLaunchEvent(AppLaunchEvent event) {
|
||||
switch (event.getType()) {
|
||||
case REVEAL_APP -> fxApplicationStarter.get(hasTrayIcon).thenAccept(FxApplication::showMainWindow);
|
||||
case OPEN_FILE -> fxApplicationStarter.get(hasTrayIcon).thenRun(() -> {
|
||||
case REVEAL_APP -> fxApplicationStarter.get().thenAccept(FxApplication::showMainWindow);
|
||||
case OPEN_FILE -> fxApplicationStarter.get().thenRun(() -> {
|
||||
Platform.runLater(() -> {
|
||||
event.getPathsToOpen().forEach(this::addVault);
|
||||
event.getPathsToOpen().forEach(this::addOrRevealVault);
|
||||
});
|
||||
});
|
||||
default -> LOG.warn("Unsupported event type: {}", event.getType());
|
||||
@@ -63,13 +64,18 @@ class AppLaunchEventHandler {
|
||||
}
|
||||
|
||||
// TODO dedup MainWindowController...
|
||||
private void addVault(Path potentialVaultPath) {
|
||||
private void addOrRevealVault(Path potentialVaultPath) {
|
||||
assert Platform.isFxApplicationThread();
|
||||
try {
|
||||
final Vault v;
|
||||
if (potentialVaultPath.getFileName().toString().equals(MASTERKEY_FILENAME)) {
|
||||
vaultListManager.add(potentialVaultPath.getParent());
|
||||
v = vaultListManager.add(potentialVaultPath.getParent());
|
||||
} else {
|
||||
vaultListManager.add(potentialVaultPath);
|
||||
v = vaultListManager.add(potentialVaultPath);
|
||||
}
|
||||
|
||||
if (v.isUnlocked()) {
|
||||
fxApplicationStarter.get().thenAccept(app -> app.getVaultService().reveal(v));
|
||||
}
|
||||
LOG.debug("Added vault {}", potentialVaultPath);
|
||||
} catch (NoSuchFileException e) {
|
||||
|
||||
@@ -83,7 +83,7 @@ public class AppLifecycleListener {
|
||||
if (allowQuitWithoutPrompt.get()) {
|
||||
decoratedQuitResponse.performQuit();
|
||||
} else {
|
||||
fxApplicationStarter.get(true).thenAccept(app -> app.showQuitWindow(decoratedQuitResponse));
|
||||
fxApplicationStarter.get().thenAccept(app -> app.showQuitWindow(decoratedQuitResponse));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,11 +113,11 @@ public class AppLifecycleListener {
|
||||
}
|
||||
|
||||
private void showPreferencesWindow(@SuppressWarnings("unused") EventObject actionEvent) {
|
||||
fxApplicationStarter.get(true).thenAccept(app -> app.showPreferencesWindow(SelectedPreferencesTab.ANY));
|
||||
fxApplicationStarter.get().thenAccept(app -> app.showPreferencesWindow(SelectedPreferencesTab.ANY));
|
||||
}
|
||||
|
||||
private void showAboutWindow(@SuppressWarnings("unused") AboutEvent aboutEvent) {
|
||||
fxApplicationStarter.get(true).thenAccept(app -> app.showPreferencesWindow(SelectedPreferencesTab.ABOUT));
|
||||
fxApplicationStarter.get().thenAccept(app -> app.showPreferencesWindow(SelectedPreferencesTab.ABOUT));
|
||||
}
|
||||
|
||||
private void forceUnmountRemainingVaults() {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.cryptomator.ui.launcher;
|
||||
|
||||
import dagger.Lazy;
|
||||
import org.cryptomator.ui.fxapp.FxApplication;
|
||||
import org.cryptomator.ui.fxapp.FxApplicationComponent;
|
||||
import org.slf4j.Logger;
|
||||
@@ -18,37 +19,36 @@ public class FxApplicationStarter {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(FxApplicationStarter.class);
|
||||
|
||||
private final FxApplicationComponent.Builder fxAppComponent;
|
||||
private final Lazy<FxApplicationComponent> fxAppComponent;
|
||||
private final ExecutorService executor;
|
||||
private final AtomicBoolean started;
|
||||
private final CompletableFuture<FxApplication> future;
|
||||
|
||||
@Inject
|
||||
public FxApplicationStarter(FxApplicationComponent.Builder fxAppComponent, ExecutorService executor) {
|
||||
public FxApplicationStarter(Lazy<FxApplicationComponent> fxAppComponent, ExecutorService executor) {
|
||||
this.fxAppComponent = fxAppComponent;
|
||||
this.executor = executor;
|
||||
this.started = new AtomicBoolean();
|
||||
this.future = new CompletableFuture<>();
|
||||
}
|
||||
|
||||
public CompletionStage<FxApplication> get(boolean hasTrayIcon) {
|
||||
public CompletionStage<FxApplication> get() {
|
||||
if (!started.getAndSet(true)) {
|
||||
start(hasTrayIcon);
|
||||
start();
|
||||
}
|
||||
return future;
|
||||
}
|
||||
|
||||
private void start(boolean hasTrayIcon) {
|
||||
private void start() {
|
||||
executor.submit(() -> {
|
||||
LOG.debug("Starting JavaFX runtime...");
|
||||
Platform.startup(() -> {
|
||||
assert Platform.isFxApplicationThread();
|
||||
LOG.info("JavaFX Runtime started.");
|
||||
FxApplication app = fxAppComponent.trayMenuSupported(hasTrayIcon).build().application();
|
||||
FxApplication app = fxAppComponent.get().application();
|
||||
app.start();
|
||||
future.complete(app);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.cryptomator.ui.launcher;
|
||||
|
||||
import dagger.Lazy;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.integrations.tray.TrayIntegrationProvider;
|
||||
@@ -24,60 +25,66 @@ public class UiLauncher {
|
||||
|
||||
private final Settings settings;
|
||||
private final ObservableList<Vault> vaults;
|
||||
private final TrayMenuComponent.Builder trayComponent;
|
||||
private final Lazy<TrayMenuComponent> trayMenu;
|
||||
private final FxApplicationStarter fxApplicationStarter;
|
||||
private final AppLaunchEventHandler launchEventHandler;
|
||||
private final Optional<TrayIntegrationProvider> trayIntegration;
|
||||
|
||||
@Inject
|
||||
public UiLauncher(Settings settings, ObservableList<Vault> vaults, TrayMenuComponent.Builder trayComponent, FxApplicationStarter fxApplicationStarter, AppLaunchEventHandler launchEventHandler, Optional<TrayIntegrationProvider> trayIntegration) {
|
||||
public UiLauncher(Settings settings, ObservableList<Vault> vaults, Lazy<TrayMenuComponent> trayMenu, FxApplicationStarter fxApplicationStarter, AppLaunchEventHandler launchEventHandler, Optional<TrayIntegrationProvider> trayIntegration) {
|
||||
this.settings = settings;
|
||||
this.vaults = vaults;
|
||||
this.trayComponent = trayComponent;
|
||||
this.trayMenu = trayMenu;
|
||||
this.fxApplicationStarter = fxApplicationStarter;
|
||||
this.launchEventHandler = launchEventHandler;
|
||||
this.trayIntegration = trayIntegration;
|
||||
}
|
||||
|
||||
public void launch() {
|
||||
final boolean hasTrayIcon;
|
||||
if (SystemTray.isSupported()) {
|
||||
trayComponent.build().addIconToSystemTray();
|
||||
hasTrayIcon = true;
|
||||
boolean hidden = settings.startHidden().get();
|
||||
if (SystemTray.isSupported() && settings.showTrayIcon().get()) {
|
||||
trayMenu.get().initializeTrayIcon();
|
||||
launch(true, hidden);
|
||||
} else {
|
||||
hasTrayIcon = false;
|
||||
launch(false, hidden);
|
||||
}
|
||||
}
|
||||
|
||||
// show window on start?
|
||||
if (hasTrayIcon && settings.startHidden().get()) {
|
||||
private void launch(boolean withTrayIcon, boolean hidden) {
|
||||
// start hidden, minimized or normal?
|
||||
if (withTrayIcon && hidden) {
|
||||
LOG.debug("Hiding application...");
|
||||
trayIntegration.ifPresent(TrayIntegrationProvider::minimizedToTray);
|
||||
} else if (!withTrayIcon && hidden) {
|
||||
LOG.debug("Minimizing application...");
|
||||
showMainWindowAsync(true);
|
||||
} else {
|
||||
showMainWindowAsync(hasTrayIcon);
|
||||
LOG.debug("Showing application...");
|
||||
showMainWindowAsync(false);
|
||||
}
|
||||
|
||||
// register app reopen listener
|
||||
Desktop.getDesktop().addAppEventListener((AppReopenedListener) e -> showMainWindowAsync(hasTrayIcon));
|
||||
Desktop.getDesktop().addAppEventListener((AppReopenedListener) e -> showMainWindowAsync(false));
|
||||
|
||||
// auto unlock
|
||||
Collection<Vault> vaultsToAutoUnlock = vaults.filtered(this::shouldAttemptAutoUnlock);
|
||||
if (!vaultsToAutoUnlock.isEmpty()) {
|
||||
fxApplicationStarter.get(hasTrayIcon).thenAccept(app -> {
|
||||
fxApplicationStarter.get().thenAccept(app -> {
|
||||
for (Vault vault : vaultsToAutoUnlock) {
|
||||
app.startUnlockWorkflow(vault, Optional.empty());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
launchEventHandler.startHandlingLaunchEvents(hasTrayIcon);
|
||||
launchEventHandler.startHandlingLaunchEvents();
|
||||
}
|
||||
|
||||
private boolean shouldAttemptAutoUnlock(Vault vault) {
|
||||
return vault.isLocked() && vault.getVaultSettings().unlockAfterStartup().get();
|
||||
}
|
||||
|
||||
private void showMainWindowAsync(boolean hasTrayIcon) {
|
||||
fxApplicationStarter.get(hasTrayIcon).thenAccept(FxApplication::showMainWindow);
|
||||
private void showMainWindowAsync(boolean minimize) {
|
||||
fxApplicationStarter.get().thenCompose(FxApplication::showMainWindow).thenAccept(win -> win.setIconified(minimize));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,18 @@ import java.util.concurrent.BlockingQueue;
|
||||
@Module(subcomponents = {TrayMenuComponent.class, FxApplicationComponent.class})
|
||||
public abstract class UiLauncherModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static TrayMenuComponent provideTrayMenuComponent(TrayMenuComponent.Builder builder) {
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static FxApplicationComponent provideFxApplicationComponent(FxApplicationComponent.Builder builder) {
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static Optional<UiAppearanceProvider> provideAppearanceProvider() {
|
||||
|
||||
@@ -6,7 +6,7 @@ import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FXMLLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
@@ -40,8 +40,8 @@ abstract class LockModule {
|
||||
@Provides
|
||||
@LockWindow
|
||||
@LockScoped
|
||||
static FXMLLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FXMLLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -63,15 +63,15 @@ abstract class LockModule {
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.LOCK_FORCED)
|
||||
@LockScoped
|
||||
static Scene provideForceLockScene(@LockWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/lock_forced.fxml");
|
||||
static Scene provideForceLockScene(@LockWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.LOCK_FORCED);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.LOCK_FAILED)
|
||||
@LockScoped
|
||||
static Scene provideLockFailedScene(@LockWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/lock_failed.fxml");
|
||||
static Scene provideLockFailedScene(@LockWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.LOCK_FAILED);
|
||||
}
|
||||
|
||||
// ------------------
|
||||
|
||||
@@ -26,7 +26,6 @@ public interface MainWindowComponent {
|
||||
default Stage showMainWindow() {
|
||||
Stage stage = window();
|
||||
stage.setScene(scene().get());
|
||||
stage.setIconified(false);
|
||||
stage.show();
|
||||
stage.toFront();
|
||||
stage.requestFocus();
|
||||
|
||||
@@ -6,7 +6,7 @@ import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.addvaultwizard.AddVaultWizardComponent;
|
||||
import org.cryptomator.ui.common.FXMLLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
@@ -39,8 +39,8 @@ abstract class MainWindowModule {
|
||||
@Provides
|
||||
@MainWindow
|
||||
@MainWindowScoped
|
||||
static FXMLLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, MainWindowSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FXMLLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, MainWindowSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -60,8 +60,8 @@ abstract class MainWindowModule {
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.MAIN_WINDOW)
|
||||
@MainWindowScoped
|
||||
static Scene provideMainScene(@MainWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/main_window.fxml");
|
||||
static Scene provideMainScene(@MainWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.MAIN_WINDOW);
|
||||
}
|
||||
|
||||
// ------------------
|
||||
|
||||
+23
-14
@@ -7,13 +7,14 @@ import org.cryptomator.ui.fxapp.FxApplication;
|
||||
import org.cryptomator.ui.fxapp.UpdateChecker;
|
||||
import org.cryptomator.ui.launcher.AppLifecycleListener;
|
||||
import org.cryptomator.ui.preferences.SelectedPreferencesTab;
|
||||
import org.cryptomator.ui.traymenu.TrayMenuComponent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.BooleanBinding;
|
||||
import javafx.beans.property.ReadOnlyBooleanProperty;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.stage.Stage;
|
||||
@@ -23,32 +24,31 @@ public class MainWindowTitleController implements FxController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MainWindowTitleController.class);
|
||||
|
||||
public HBox titleBar;
|
||||
|
||||
private final AppLifecycleListener appLifecycle;
|
||||
private final Stage window;
|
||||
private final FxApplication application;
|
||||
private final boolean minimizeToSysTray;
|
||||
private final boolean trayMenuInitialized;
|
||||
private final UpdateChecker updateChecker;
|
||||
private final BooleanBinding updateAvailable;
|
||||
private final LicenseHolder licenseHolder;
|
||||
private final Settings settings;
|
||||
private final BooleanBinding debugModeEnabled;
|
||||
private final BooleanBinding showMinimizeButton;
|
||||
|
||||
public HBox titleBar;
|
||||
private double xOffset;
|
||||
private double yOffset;
|
||||
|
||||
@Inject
|
||||
MainWindowTitleController(AppLifecycleListener appLifecycle, @MainWindow Stage window, FxApplication application, @Named("trayMenuSupported") boolean minimizeToSysTray, UpdateChecker updateChecker, LicenseHolder licenseHolder, Settings settings) {
|
||||
MainWindowTitleController(AppLifecycleListener appLifecycle, @MainWindow Stage window, FxApplication application, TrayMenuComponent trayMenu, UpdateChecker updateChecker, LicenseHolder licenseHolder, Settings settings) {
|
||||
this.appLifecycle = appLifecycle;
|
||||
this.window = window;
|
||||
this.application = application;
|
||||
this.minimizeToSysTray = minimizeToSysTray;
|
||||
this.trayMenuInitialized = trayMenu.isInitialized();
|
||||
this.updateChecker = updateChecker;
|
||||
this.updateAvailable = updateChecker.latestVersionProperty().isNotNull();
|
||||
this.licenseHolder = licenseHolder;
|
||||
this.settings = settings;
|
||||
this.debugModeEnabled = Bindings.createBooleanBinding(this::isDebugModeEnabled, settings.debugMode());
|
||||
this.showMinimizeButton = Bindings.createBooleanBinding(this::isShowMinimizeButton, settings.showMinimizeButton(), settings.showTrayIcon());
|
||||
}
|
||||
|
||||
@FXML
|
||||
@@ -71,7 +71,7 @@ public class MainWindowTitleController implements FxController {
|
||||
|
||||
@FXML
|
||||
public void close() {
|
||||
if (minimizeToSysTray) {
|
||||
if (trayMenuInitialized) {
|
||||
window.close();
|
||||
} else {
|
||||
appLifecycle.quit();
|
||||
@@ -112,15 +112,24 @@ public class MainWindowTitleController implements FxController {
|
||||
return updateAvailable.get();
|
||||
}
|
||||
|
||||
public boolean isMinimizeToSysTray() {
|
||||
return minimizeToSysTray;
|
||||
public boolean isTrayIconPresent() {
|
||||
return trayMenuInitialized;
|
||||
}
|
||||
|
||||
public BooleanBinding debugModeEnabledProperty() {
|
||||
return debugModeEnabled;
|
||||
public ReadOnlyBooleanProperty debugModeEnabledProperty() {
|
||||
return settings.debugMode();
|
||||
}
|
||||
|
||||
public boolean isDebugModeEnabled() {
|
||||
return settings.debugMode().get();
|
||||
return debugModeEnabledProperty().get();
|
||||
}
|
||||
|
||||
public BooleanBinding showMinimizeButtonProperty() {
|
||||
return showMinimizeButton;
|
||||
}
|
||||
|
||||
public boolean isShowMinimizeButton() {
|
||||
// always show the minimize button if no tray icon is present OR it is explicitily enabled
|
||||
return !trayMenuInitialized || settings.showMinimizeButton().get();
|
||||
}
|
||||
}
|
||||
|
||||
+7
-1
@@ -5,6 +5,7 @@ import org.cryptomator.common.keychain.KeychainManager;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.fxapp.FxApplication;
|
||||
import org.cryptomator.ui.vaultoptions.SelectedVaultOptionsTab;
|
||||
import org.cryptomator.ui.vaultoptions.VaultOptionsComponent;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -47,7 +48,12 @@ public class VaultDetailLockedController implements FxController {
|
||||
|
||||
@FXML
|
||||
public void showVaultOptions() {
|
||||
vaultOptionsWindow.vault(vault.get()).build().showVaultOptionsWindow();
|
||||
vaultOptionsWindow.vault(vault.get()).build().showVaultOptionsWindow(SelectedVaultOptionsTab.ANY);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void showKeyVaultOptions() {
|
||||
vaultOptionsWindow.vault(vault.get()).build().showVaultOptionsWindow(SelectedVaultOptionsTab.KEY);
|
||||
}
|
||||
|
||||
/* Getter/Setter */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.cryptomator.ui.mainwindow;
|
||||
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.FXMLLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.controls.DraggableListCell;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -17,10 +17,10 @@ import java.io.UncheckedIOException;
|
||||
@MainWindowScoped
|
||||
public class VaultListCellFactory implements Callback<ListView<Vault>, ListCell<Vault>> {
|
||||
|
||||
private final FXMLLoaderFactory fxmlLoaders;
|
||||
private final FxmlLoaderFactory fxmlLoaders;
|
||||
|
||||
@Inject
|
||||
VaultListCellFactory(@MainWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
VaultListCellFactory(@MainWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
this.fxmlLoaders = fxmlLoaders;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import org.cryptomator.cryptofs.common.FileSystemCapabilityChecker;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FXMLLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
@@ -30,8 +30,8 @@ abstract class MigrationModule {
|
||||
@Provides
|
||||
@MigrationWindow
|
||||
@MigrationScoped
|
||||
static FXMLLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FXMLLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -56,36 +56,36 @@ abstract class MigrationModule {
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.MIGRATION_START)
|
||||
@MigrationScoped
|
||||
static Scene provideMigrationStartScene(@MigrationWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/migration_start.fxml");
|
||||
static Scene provideMigrationStartScene(@MigrationWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.MIGRATION_START);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.MIGRATION_RUN)
|
||||
@MigrationScoped
|
||||
static Scene provideMigrationRunScene(@MigrationWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/migration_run.fxml");
|
||||
static Scene provideMigrationRunScene(@MigrationWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.MIGRATION_RUN);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.MIGRATION_SUCCESS)
|
||||
@MigrationScoped
|
||||
static Scene provideMigrationSuccessScene(@MigrationWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/migration_success.fxml");
|
||||
static Scene provideMigrationSuccessScene(@MigrationWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.MIGRATION_SUCCESS);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.MIGRATION_CAPABILITY_ERROR)
|
||||
@MigrationScoped
|
||||
static Scene provideMigrationCapabilityErrorScene(@MigrationWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/migration_capability_error.fxml");
|
||||
static Scene provideMigrationCapabilityErrorScene(@MigrationWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.MIGRATION_CAPABILITY_ERROR);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.MIGRATION_IMPOSSIBLE)
|
||||
@MigrationScoped
|
||||
static Scene provideMigrationImpossibleScene(@MigrationWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/migration_impossible.fxml");
|
||||
static Scene provideMigrationImpossibleScene(@MigrationWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.MIGRATION_IMPOSSIBLE);
|
||||
}
|
||||
|
||||
// ------------------
|
||||
|
||||
+19
-8
@@ -10,11 +10,11 @@ import org.cryptomator.integrations.autostart.ToggleAutoStartFailedException;
|
||||
import org.cryptomator.integrations.keychain.KeychainAccessProvider;
|
||||
import org.cryptomator.ui.common.ErrorComponent;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.traymenu.TrayMenuComponent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javafx.application.Application;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
@@ -31,7 +31,6 @@ import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@PreferencesScoped
|
||||
@@ -41,11 +40,11 @@ public class GeneralPreferencesController implements FxController {
|
||||
|
||||
private final Stage window;
|
||||
private final Settings settings;
|
||||
private final boolean trayMenuInitialized;
|
||||
private final boolean trayMenuSupported;
|
||||
private final Optional<AutoStartProvider> autoStartProvider;
|
||||
private final ObjectProperty<SelectedPreferencesTab> selectedTabProperty;
|
||||
private final LicenseHolder licenseHolder;
|
||||
private final ExecutorService executor;
|
||||
private final ResourceBundle resourceBundle;
|
||||
private final Application application;
|
||||
private final Environment environment;
|
||||
@@ -53,6 +52,8 @@ public class GeneralPreferencesController implements FxController {
|
||||
private final ErrorComponent.Builder errorComponent;
|
||||
public ChoiceBox<UiTheme> themeChoiceBox;
|
||||
public ChoiceBox<KeychainBackend> keychainBackendChoiceBox;
|
||||
public CheckBox showMinimizeButtonCheckbox;
|
||||
public CheckBox showTrayIconCheckbox;
|
||||
public CheckBox startHiddenCheckbox;
|
||||
public CheckBox debugModeCheckbox;
|
||||
public CheckBox autoStartCheckbox;
|
||||
@@ -60,16 +61,17 @@ public class GeneralPreferencesController implements FxController {
|
||||
public RadioButton nodeOrientationLtr;
|
||||
public RadioButton nodeOrientationRtl;
|
||||
|
||||
|
||||
@Inject
|
||||
GeneralPreferencesController(@PreferencesWindow Stage window, Settings settings, @Named("trayMenuSupported") boolean trayMenuSupported, Optional<AutoStartProvider> autoStartProvider, Set<KeychainAccessProvider> keychainAccessProviders, ObjectProperty<SelectedPreferencesTab> selectedTabProperty, LicenseHolder licenseHolder, ExecutorService executor, ResourceBundle resourceBundle, Application application, Environment environment, ErrorComponent.Builder errorComponent) {
|
||||
GeneralPreferencesController(@PreferencesWindow Stage window, Settings settings, TrayMenuComponent trayMenu, Optional<AutoStartProvider> autoStartProvider, Set<KeychainAccessProvider> keychainAccessProviders, ObjectProperty<SelectedPreferencesTab> selectedTabProperty, LicenseHolder licenseHolder, ResourceBundle resourceBundle, Application application, Environment environment, ErrorComponent.Builder errorComponent) {
|
||||
this.window = window;
|
||||
this.settings = settings;
|
||||
this.trayMenuSupported = trayMenuSupported;
|
||||
this.trayMenuInitialized = trayMenu.isInitialized();
|
||||
this.trayMenuSupported = trayMenu.isSupported();
|
||||
this.autoStartProvider = autoStartProvider;
|
||||
this.keychainAccessProviders = keychainAccessProviders;
|
||||
this.selectedTabProperty = selectedTabProperty;
|
||||
this.licenseHolder = licenseHolder;
|
||||
this.executor = executor;
|
||||
this.resourceBundle = resourceBundle;
|
||||
this.application = application;
|
||||
this.environment = environment;
|
||||
@@ -85,6 +87,10 @@ public class GeneralPreferencesController implements FxController {
|
||||
themeChoiceBox.valueProperty().bindBidirectional(settings.theme());
|
||||
themeChoiceBox.setConverter(new UiThemeConverter(resourceBundle));
|
||||
|
||||
showMinimizeButtonCheckbox.selectedProperty().bindBidirectional(settings.showMinimizeButton());
|
||||
|
||||
showTrayIconCheckbox.selectedProperty().bindBidirectional(settings.showTrayIcon());
|
||||
|
||||
startHiddenCheckbox.selectedProperty().bindBidirectional(settings.startHidden());
|
||||
|
||||
debugModeCheckbox.selectedProperty().bindBidirectional(settings.debugMode());
|
||||
@@ -105,8 +111,12 @@ public class GeneralPreferencesController implements FxController {
|
||||
return Arrays.stream(KeychainBackend.values()).filter(value -> namesOfAvailableProviders.contains(value.getProviderClass())).toArray(KeychainBackend[]::new);
|
||||
}
|
||||
|
||||
public boolean isTrayMenuInitialized() {
|
||||
return trayMenuInitialized;
|
||||
}
|
||||
|
||||
public boolean isTrayMenuSupported() {
|
||||
return this.trayMenuSupported;
|
||||
return trayMenuSupported;
|
||||
}
|
||||
|
||||
public boolean isAutoStartSupported() {
|
||||
@@ -175,6 +185,7 @@ public class GeneralPreferencesController implements FxController {
|
||||
public UiTheme fromString(String string) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class KeychainBackendConverter extends StringConverter<KeychainBackend> {
|
||||
@@ -194,6 +205,6 @@ public class GeneralPreferencesController implements FxController {
|
||||
public KeychainBackend fromString(String string) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FXMLLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
@@ -32,8 +32,8 @@ abstract class PreferencesModule {
|
||||
@Provides
|
||||
@PreferencesWindow
|
||||
@PreferencesScoped
|
||||
static FXMLLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FXMLLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -49,8 +49,8 @@ abstract class PreferencesModule {
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.PREFERENCES)
|
||||
@PreferencesScoped
|
||||
static Scene providePreferencesScene(@PreferencesWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/preferences.fxml");
|
||||
static Scene providePreferencesScene(@PreferencesWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.PREFERENCES);
|
||||
}
|
||||
|
||||
// ------------------
|
||||
|
||||
@@ -5,7 +5,7 @@ import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FXMLLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
@@ -25,8 +25,8 @@ abstract class QuitModule {
|
||||
@Provides
|
||||
@QuitWindow
|
||||
@QuitScoped
|
||||
static FXMLLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FXMLLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -43,8 +43,8 @@ abstract class QuitModule {
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.QUIT)
|
||||
@QuitScoped
|
||||
static Scene provideQuitScene(@QuitWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/quit.fxml");
|
||||
static Scene provideQuitScene(@QuitWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.QUIT);
|
||||
}
|
||||
|
||||
// ------------------
|
||||
|
||||
@@ -6,7 +6,7 @@ import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FXMLLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
@@ -33,8 +33,8 @@ abstract class RecoveryKeyModule {
|
||||
@Provides
|
||||
@RecoveryKeyWindow
|
||||
@RecoveryKeyScoped
|
||||
static FXMLLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FXMLLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -69,29 +69,29 @@ abstract class RecoveryKeyModule {
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.RECOVERYKEY_CREATE)
|
||||
@RecoveryKeyScoped
|
||||
static Scene provideRecoveryKeyCreationScene(@RecoveryKeyWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/recoverykey_create.fxml");
|
||||
static Scene provideRecoveryKeyCreationScene(@RecoveryKeyWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.RECOVERYKEY_CREATE);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.RECOVERYKEY_SUCCESS)
|
||||
@RecoveryKeyScoped
|
||||
static Scene provideRecoveryKeySuccessScene(@RecoveryKeyWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/recoverykey_success.fxml");
|
||||
static Scene provideRecoveryKeySuccessScene(@RecoveryKeyWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.RECOVERYKEY_SUCCESS);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.RECOVERYKEY_RECOVER)
|
||||
@RecoveryKeyScoped
|
||||
static Scene provideRecoveryKeyRecoverScene(@RecoveryKeyWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/recoverykey_recover.fxml");
|
||||
static Scene provideRecoveryKeyRecoverScene(@RecoveryKeyWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.RECOVERYKEY_RECOVER);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.RECOVERYKEY_RESET_PASSWORD)
|
||||
@RecoveryKeyScoped
|
||||
static Scene provideRecoveryKeyResetPasswordScene(@RecoveryKeyWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/recoverykey_reset_password.fxml");
|
||||
static Scene provideRecoveryKeyResetPasswordScene(@RecoveryKeyWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.RECOVERYKEY_RESET_PASSWORD);
|
||||
}
|
||||
|
||||
// ------------------
|
||||
|
||||
@@ -5,7 +5,7 @@ import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FXMLLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
@@ -26,8 +26,8 @@ abstract class RemoveVaultModule {
|
||||
@Provides
|
||||
@RemoveVaultWindow
|
||||
@RemoveVaultScoped
|
||||
static FXMLLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FXMLLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -45,8 +45,8 @@ abstract class RemoveVaultModule {
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.REMOVE_VAULT)
|
||||
@RemoveVaultScoped
|
||||
static Scene provideRemoveVaultScene(@RemoveVaultWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/remove_vault.fxml");
|
||||
static Scene provideRemoveVaultScene(@RemoveVaultWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.REMOVE_VAULT);
|
||||
}
|
||||
|
||||
// ------------------
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package org.cryptomator.ui.stats;
|
||||
|
||||
import javafx.beans.NamedArg;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.geometry.Point2D;
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.chart.AreaChart;
|
||||
import javafx.scene.chart.Axis;
|
||||
import javafx.scene.shape.ClosePath;
|
||||
import javafx.scene.shape.CubicCurveTo;
|
||||
import javafx.scene.shape.LineTo;
|
||||
import javafx.scene.shape.MoveTo;
|
||||
import javafx.scene.shape.Path;
|
||||
import javafx.scene.shape.PathElement;
|
||||
|
||||
// inspired by http://fxexperience.com/2012/01/curve-fitting-and-styling-areachart/
|
||||
public class SmoothAreaChart extends AreaChart<Number, Number> {
|
||||
|
||||
public SmoothAreaChart(@NamedArg("xAxis") Axis<Number> xAxis, @NamedArg("yAxis") Axis<Number> yAxis) {
|
||||
super(xAxis, yAxis);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void layoutPlotChildren() {
|
||||
super.layoutPlotChildren();
|
||||
var iter = getDisplayedSeriesIterator();
|
||||
while (iter.hasNext()) {
|
||||
var series = iter.next();
|
||||
final Path seriesLine = (Path)((Group)series.getNode()).getChildren().get(1);
|
||||
final Path fillPath = (Path)((Group)series.getNode()).getChildren().get(0);
|
||||
var dx = getXAxis().getWidth() / series.getData().size();
|
||||
smooth(seriesLine.getElements(), fillPath.getElements(), dx);
|
||||
}
|
||||
}
|
||||
|
||||
private static void smooth(ObservableList<PathElement> strokeElements, ObservableList<PathElement> fillElements, double dx) {
|
||||
// as we do not have direct access to the data, first recreate the list of all the data points we have
|
||||
final Point2D[] dataPoints = new Point2D[strokeElements.size()];
|
||||
for (int i = 0; i < strokeElements.size(); i++) {
|
||||
final PathElement element = strokeElements.get(i);
|
||||
if (element instanceof MoveTo) {
|
||||
final MoveTo move = (MoveTo)element;
|
||||
dataPoints[i] = new Point2D(move.getX(), move.getY());
|
||||
} else if (element instanceof LineTo) {
|
||||
final LineTo line = (LineTo)element;
|
||||
final double x = line.getX(), y = line.getY();
|
||||
dataPoints[i] = new Point2D(x, y);
|
||||
}
|
||||
}
|
||||
// next we need to know the zero Y value
|
||||
final double zeroY = ((MoveTo) fillElements.get(0)).getY();
|
||||
final double dx2 = dx / 2.0;
|
||||
|
||||
// now clear and rebuild elements
|
||||
strokeElements.clear();
|
||||
fillElements.clear();
|
||||
// start both paths
|
||||
strokeElements.add(new MoveTo(dataPoints[0].getX(),dataPoints[0].getY()));
|
||||
fillElements.add(new MoveTo(dataPoints[0].getX(),zeroY));
|
||||
fillElements.add(new LineTo(dataPoints[0].getX(),dataPoints[0].getY()));
|
||||
// add curves
|
||||
for (int i = 1; i < dataPoints.length; i++) {
|
||||
final int ci = i-1;
|
||||
strokeElements.add(new CubicCurveTo(
|
||||
dataPoints[ci].getX() + dx2, dataPoints[ci].getY(),
|
||||
dataPoints[i].getX() - dx2, dataPoints[i].getY(),
|
||||
dataPoints[i].getX(), dataPoints[i].getY()));
|
||||
fillElements.add(new CubicCurveTo(
|
||||
dataPoints[ci].getX() + dx2, dataPoints[ci].getY(),
|
||||
dataPoints[i].getX() - dx2, dataPoints[i].getY(),
|
||||
dataPoints[i].getX(),dataPoints[i].getY()));
|
||||
}
|
||||
// end the paths
|
||||
fillElements.add(new LineTo(dataPoints[dataPoints.length-1].getX(),zeroY));
|
||||
fillElements.add(new ClosePath());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import javafx.stage.Stage;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.common.vaults.VaultState;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FXMLLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
@@ -29,8 +29,8 @@ abstract class VaultStatisticsModule {
|
||||
@Provides
|
||||
@VaultStatisticsWindow
|
||||
@VaultStatisticsScoped
|
||||
static FXMLLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FXMLLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -60,8 +60,8 @@ abstract class VaultStatisticsModule {
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.VAULT_STATISTICS)
|
||||
@VaultStatisticsScoped
|
||||
static Scene provideVaultStatisticsScene(@VaultStatisticsWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/stats.fxml");
|
||||
static Scene provideVaultStatisticsScene(@VaultStatisticsWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.VAULT_STATISTICS);
|
||||
}
|
||||
|
||||
// ------------------
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.cryptomator.ui.traymenu;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.integrations.uiappearance.Theme;
|
||||
import org.cryptomator.integrations.uiappearance.UiAppearanceException;
|
||||
@@ -22,6 +23,7 @@ public class TrayIconController {
|
||||
private final Optional<UiAppearanceProvider> appearanceProvider;
|
||||
private final TrayMenuController trayMenuController;
|
||||
private final TrayIcon trayIcon;
|
||||
private volatile boolean initialized;
|
||||
|
||||
@Inject
|
||||
TrayIconController(TrayImageFactory imageFactory, TrayMenuController trayMenuController, Optional<UiAppearanceProvider> appearanceProvider) {
|
||||
@@ -31,7 +33,9 @@ public class TrayIconController {
|
||||
this.trayIcon = new TrayIcon(imageFactory.loadImage(), "Cryptomator", trayMenuController.getMenu());
|
||||
}
|
||||
|
||||
public void initializeTrayIcon() {
|
||||
public synchronized void initializeTrayIcon() throws IllegalStateException {
|
||||
Preconditions.checkState(!initialized);
|
||||
|
||||
appearanceProvider.ifPresent(appearanceProvider -> {
|
||||
try {
|
||||
appearanceProvider.addListener(this::systemInterfaceThemeChanged);
|
||||
@@ -53,10 +57,15 @@ public class TrayIconController {
|
||||
}
|
||||
|
||||
trayMenuController.initTrayMenu();
|
||||
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
private void systemInterfaceThemeChanged(Theme theme) {
|
||||
trayIcon.setImage(imageFactory.loadImage()); // TODO refactor "theme" is re-queried in loadImage()
|
||||
}
|
||||
|
||||
public boolean isInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,19 +5,38 @@
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.ui.traymenu;
|
||||
|
||||
import dagger.Lazy;
|
||||
import dagger.Subcomponent;
|
||||
|
||||
import java.awt.SystemTray;
|
||||
|
||||
@TrayMenuScoped
|
||||
@Subcomponent
|
||||
public interface TrayMenuComponent {
|
||||
|
||||
TrayIconController trayIconController();
|
||||
Lazy<TrayIconController> trayIconController();
|
||||
|
||||
default void addIconToSystemTray() {
|
||||
assert SystemTray.isSupported();
|
||||
trayIconController().initializeTrayIcon();
|
||||
/**
|
||||
* @return <code>true</code> if a tray icon can be installed
|
||||
*/
|
||||
default boolean isSupported() {
|
||||
return SystemTray.isSupported();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if a tray icon has been installed
|
||||
*/
|
||||
default boolean isInitialized() {
|
||||
return isSupported() && trayIconController().get().isInitialized();
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs a tray icon to the system tray.
|
||||
*
|
||||
* @throws IllegalStateException If already added
|
||||
*/
|
||||
default void initializeTrayIcon() throws IllegalStateException {
|
||||
assert isSupported();
|
||||
trayIconController().get().initializeTrayIcon();
|
||||
}
|
||||
|
||||
@Subcomponent.Builder
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.cryptomator.ui.traymenu;
|
||||
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.fxapp.FxApplication;
|
||||
import org.cryptomator.ui.launcher.AppLifecycleListener;
|
||||
import org.cryptomator.ui.launcher.FxApplicationStarter;
|
||||
import org.cryptomator.ui.preferences.SelectedPreferencesTab;
|
||||
@@ -103,32 +104,36 @@ class TrayMenuController {
|
||||
return actionEvent -> consumer.accept(vault);
|
||||
}
|
||||
|
||||
private void unlockVault(Vault vault) {
|
||||
fxApplicationStarter.get(true).thenAccept(app -> app.startUnlockWorkflow(vault, Optional.empty()));
|
||||
}
|
||||
|
||||
private void lockVault(Vault vault) {
|
||||
fxApplicationStarter.get(true).thenAccept(app -> app.startLockWorkflow(vault, Optional.empty()));
|
||||
}
|
||||
|
||||
private void lockAllVaults(ActionEvent actionEvent) {
|
||||
fxApplicationStarter.get(true).thenAccept(app -> app.getVaultService().lockAll(vaults.filtered(Vault::isUnlocked), false));
|
||||
}
|
||||
|
||||
private void revealVault(Vault vault) {
|
||||
fxApplicationStarter.get(true).thenAccept(app -> app.getVaultService().reveal(vault));
|
||||
}
|
||||
|
||||
void showMainWindow(@SuppressWarnings("unused") ActionEvent actionEvent) {
|
||||
fxApplicationStarter.get(true).thenAccept(app -> app.showMainWindow());
|
||||
}
|
||||
|
||||
private void showPreferencesWindow(@SuppressWarnings("unused") EventObject actionEvent) {
|
||||
fxApplicationStarter.get(true).thenAccept(app -> app.showPreferencesWindow(SelectedPreferencesTab.ANY));
|
||||
}
|
||||
|
||||
private void quitApplication(EventObject actionEvent) {
|
||||
appLifecycle.quit();
|
||||
}
|
||||
|
||||
private void unlockVault(Vault vault) {
|
||||
showMainAppAndThen(app -> app.startUnlockWorkflow(vault, Optional.empty()));
|
||||
}
|
||||
|
||||
private void lockVault(Vault vault) {
|
||||
showMainAppAndThen(app -> app.startLockWorkflow(vault, Optional.empty()));
|
||||
}
|
||||
|
||||
private void lockAllVaults(ActionEvent actionEvent) {
|
||||
showMainAppAndThen(app -> app.getVaultService().lockAll(vaults.filtered(Vault::isUnlocked), false));
|
||||
}
|
||||
|
||||
private void revealVault(Vault vault) {
|
||||
showMainAppAndThen(app -> app.getVaultService().reveal(vault));
|
||||
}
|
||||
|
||||
void showMainWindow(@SuppressWarnings("unused") ActionEvent actionEvent) {
|
||||
showMainAppAndThen(app -> app.showMainWindow());
|
||||
}
|
||||
|
||||
private void showPreferencesWindow(@SuppressWarnings("unused") EventObject actionEvent) {
|
||||
showMainAppAndThen(app -> app.showPreferencesWindow(SelectedPreferencesTab.ANY));
|
||||
}
|
||||
|
||||
private void showMainAppAndThen(Consumer<FxApplication> action) {
|
||||
fxApplicationStarter.get().thenAccept(action);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import org.cryptomator.common.keychain.KeychainManager;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.integrations.keychain.KeychainAccessException;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FXMLLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
@@ -78,8 +78,8 @@ abstract class UnlockModule {
|
||||
@Provides
|
||||
@UnlockWindow
|
||||
@UnlockScoped
|
||||
static FXMLLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FXMLLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -101,22 +101,22 @@ abstract class UnlockModule {
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.UNLOCK)
|
||||
@UnlockScoped
|
||||
static Scene provideUnlockScene(@UnlockWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/unlock.fxml");
|
||||
static Scene provideUnlockScene(@UnlockWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.UNLOCK);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.UNLOCK_SUCCESS)
|
||||
@UnlockScoped
|
||||
static Scene provideUnlockSuccessScene(@UnlockWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/unlock_success.fxml");
|
||||
static Scene provideUnlockSuccessScene(@UnlockWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.UNLOCK_SUCCESS);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.UNLOCK_INVALID_MOUNT_POINT)
|
||||
@UnlockScoped
|
||||
static Scene provideInvalidMountPointScene(@UnlockWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/unlock_invalid_mount_point.fxml");
|
||||
static Scene provideInvalidMountPointScene(@UnlockWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.UNLOCK_INVALID_MOUNT_POINT);
|
||||
}
|
||||
|
||||
// ------------------
|
||||
|
||||
@@ -76,8 +76,8 @@ public class UnlockWorkflow extends Task<Boolean> {
|
||||
|
||||
setOnFailed(event -> {
|
||||
Throwable throwable = event.getSource().getException();
|
||||
if (throwable instanceof InvalidMountPointException) {
|
||||
handleInvalidMountPoint((InvalidMountPointException) throwable);
|
||||
if (throwable instanceof InvalidMountPointException e) {
|
||||
handleInvalidMountPoint(e);
|
||||
} else {
|
||||
handleGenericError(throwable);
|
||||
}
|
||||
@@ -165,15 +165,7 @@ public class UnlockWorkflow extends Task<Boolean> {
|
||||
assert requirement != MountPointRequirement.PARENT_OPT_MOUNT_POINT; //Not implemented anywhere (yet)
|
||||
|
||||
Throwable cause = impExc.getCause();
|
||||
//Cause is either null (cause the IMPE was thrown directly, e.g. because no MPC succeeded)
|
||||
//or the cause was not an Exception (but some other kind of Throwable)
|
||||
//Either way: Handle as generic error
|
||||
if (!(cause instanceof Exception)) {
|
||||
handleGenericError(impExc);
|
||||
return;
|
||||
}
|
||||
|
||||
//From here on handle the cause, not the caught exception
|
||||
// TODO: apply https://openjdk.java.net/jeps/8213076 in future JDK versions
|
||||
if (cause instanceof NotDirectoryException) {
|
||||
if (requirement == MountPointRequirement.PARENT_NO_MOUNT_POINT) {
|
||||
LOG.error("Unlock failed. Parent folder is missing: {}", cause.getMessage());
|
||||
@@ -182,28 +174,23 @@ public class UnlockWorkflow extends Task<Boolean> {
|
||||
}
|
||||
showInvalidMountPointScene();
|
||||
return;
|
||||
}
|
||||
|
||||
if (cause instanceof FileAlreadyExistsException) {
|
||||
} else if (cause instanceof FileAlreadyExistsException) {
|
||||
LOG.error("Unlock failed. Mountpoint already exists: {}", cause.getMessage());
|
||||
showInvalidMountPointScene();
|
||||
return;
|
||||
}
|
||||
|
||||
if (cause instanceof DirectoryNotEmptyException) {
|
||||
} else if (cause instanceof DirectoryNotEmptyException) {
|
||||
LOG.error("Unlock failed. Mountpoint not an empty directory: {}", cause.getMessage());
|
||||
showInvalidMountPointScene();
|
||||
return;
|
||||
} else {
|
||||
handleGenericError(impExc);
|
||||
}
|
||||
|
||||
//Everything else (especially IOException) results in a generic error
|
||||
//This must be done after the other exceptions because they extend IOException...
|
||||
handleGenericError(cause);
|
||||
}
|
||||
|
||||
private void showInvalidMountPointScene() {
|
||||
Platform.runLater(() -> {
|
||||
window.setScene(invalidMountPointScene.get());
|
||||
window.show();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.cryptomator.ui.vaultoptions;
|
||||
|
||||
public enum SelectedVaultOptionsTab {
|
||||
/**
|
||||
* Let the controller decide which tab to show.
|
||||
*/
|
||||
ANY,
|
||||
|
||||
/**
|
||||
* Show general tab
|
||||
*/
|
||||
GENERAL,
|
||||
|
||||
/**
|
||||
* Show mounting tab
|
||||
*/
|
||||
MOUNT,
|
||||
|
||||
/**
|
||||
* Show password tab
|
||||
*/
|
||||
KEY,
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
@@ -25,7 +26,10 @@ public interface VaultOptionsComponent {
|
||||
@FxmlScene(FxmlFile.VAULT_OPTIONS)
|
||||
Lazy<Scene> scene();
|
||||
|
||||
default void showVaultOptionsWindow() {
|
||||
ObjectProperty<SelectedVaultOptionsTab> selectedTabProperty();
|
||||
|
||||
default void showVaultOptionsWindow(SelectedVaultOptionsTab selectedTab) {
|
||||
selectedTabProperty().set(selectedTab);
|
||||
Stage stage = window();
|
||||
stage.setScene(scene().get());
|
||||
stage.show();
|
||||
|
||||
@@ -1,13 +1,67 @@
|
||||
package org.cryptomator.ui.vaultoptions;
|
||||
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.WindowEvent;
|
||||
|
||||
@VaultOptionsScoped
|
||||
public class VaultOptionsController implements FxController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(VaultOptionsController.class);
|
||||
|
||||
private final Stage window;
|
||||
private final ObjectProperty<SelectedVaultOptionsTab> selectedTabProperty;
|
||||
public TabPane tabPane;
|
||||
public Tab generalTab;
|
||||
public Tab mountTab;
|
||||
public Tab keyTab;
|
||||
|
||||
@Inject
|
||||
VaultOptionsController() {}
|
||||
VaultOptionsController(@VaultOptionsWindow Stage window, ObjectProperty<SelectedVaultOptionsTab> selectedTabProperty) {
|
||||
this.window = window;
|
||||
this.selectedTabProperty = selectedTabProperty;
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
window.setOnShowing(this::windowWillAppear);
|
||||
selectedTabProperty.addListener(observable -> this.selectChosenTab());
|
||||
tabPane.getSelectionModel().selectedItemProperty().addListener(observable -> this.selectedTabChanged());
|
||||
}
|
||||
|
||||
private void selectChosenTab() {
|
||||
Tab toBeSelected = getTabToSelect(selectedTabProperty.get());
|
||||
tabPane.getSelectionModel().select(toBeSelected);
|
||||
}
|
||||
|
||||
private Tab getTabToSelect(SelectedVaultOptionsTab selectedTab) {
|
||||
return switch (selectedTab) {
|
||||
case ANY, GENERAL -> generalTab;
|
||||
case MOUNT -> mountTab;
|
||||
case KEY -> keyTab;
|
||||
};
|
||||
}
|
||||
|
||||
private void selectedTabChanged() {
|
||||
Tab selectedTab = tabPane.getSelectionModel().getSelectedItem();
|
||||
try {
|
||||
SelectedVaultOptionsTab selectedVaultOptionsTab = SelectedVaultOptionsTab.valueOf(selectedTab.getId());
|
||||
selectedTabProperty.set(selectedVaultOptionsTab);
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.error("Unknown vault options tab id: {}", selectedTab.getId());
|
||||
}
|
||||
}
|
||||
|
||||
private void windowWillAppear(@SuppressWarnings("unused") WindowEvent windowEvent) {
|
||||
selectChosenTab();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,16 +7,18 @@ import dagger.multibindings.IntoMap;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.changepassword.ChangePasswordComponent;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FXMLLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.common.StageFactory;
|
||||
import org.cryptomator.ui.mainwindow.MainWindow;
|
||||
import org.cryptomator.ui.recoverykey.RecoveryKeyComponent;
|
||||
|
||||
import javax.inject.Provider;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
@@ -26,11 +28,17 @@ import java.util.ResourceBundle;
|
||||
@Module(subcomponents = {ChangePasswordComponent.class, RecoveryKeyComponent.class})
|
||||
abstract class VaultOptionsModule {
|
||||
|
||||
@Provides
|
||||
@VaultOptionsScoped
|
||||
static ObjectProperty<SelectedVaultOptionsTab> provideSelectedTabProperty() {
|
||||
return new SimpleObjectProperty<>(SelectedVaultOptionsTab.ANY);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@VaultOptionsWindow
|
||||
@VaultOptionsScoped
|
||||
static FXMLLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FXMLLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -50,8 +58,8 @@ abstract class VaultOptionsModule {
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.VAULT_OPTIONS)
|
||||
@VaultOptionsScoped
|
||||
static Scene provideVaultOptionsScene(@VaultOptionsWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/vault_options.fxml");
|
||||
static Scene provideVaultOptionsScene(@VaultOptionsWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.VAULT_OPTIONS);
|
||||
}
|
||||
|
||||
// ------------------
|
||||
|
||||
@@ -5,7 +5,7 @@ import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FXMLLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
@@ -26,8 +26,8 @@ abstract class WrongFileAlertModule {
|
||||
@Provides
|
||||
@WrongFileAlertWindow
|
||||
@WrongFileAlertScoped
|
||||
static FXMLLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FXMLLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -45,8 +45,8 @@ abstract class WrongFileAlertModule {
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.WRONGFILEALERT)
|
||||
@WrongFileAlertScoped
|
||||
static Scene provideWrongFileAlertScene(@WrongFileAlertWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/wrongfilealert.fxml");
|
||||
static Scene provideWrongFileAlertScene(@WrongFileAlertWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.WRONGFILEALERT);
|
||||
}
|
||||
|
||||
// ------------------
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
<Tooltip text="%main.preferencesBtn.tooltip"/>
|
||||
</tooltip>
|
||||
</Button>
|
||||
<Button contentDisplay="GRAPHIC_ONLY" mnemonicParsing="false" onAction="#minimize" focusTraversable="false" visible="${!controller.minimizeToSysTray}" managed="${!controller.minimizeToSysTray}">
|
||||
<Button contentDisplay="GRAPHIC_ONLY" mnemonicParsing="false" onAction="#minimize" focusTraversable="false" visible="${controller.showMinimizeButton}" managed="${controller.showMinimizeButton}">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="WINDOW_MINIMIZE" glyphSize="12"/>
|
||||
</graphic>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
</ImageView>
|
||||
<VBox spacing="3" HBox.hgrow="ALWAYS" alignment="CENTER_LEFT">
|
||||
<FormattedLabel styleClass="label-large" format="Cryptomator %s" arg1="${controller.applicationVersion}"/>
|
||||
<Label text="© 2016 – 2020 Skymatic GmbH"/>
|
||||
<Label text="© 2016 – 2021 Skymatic GmbH"/>
|
||||
</VBox>
|
||||
</HBox>
|
||||
|
||||
|
||||
@@ -32,7 +32,11 @@
|
||||
<RadioButton fx:id="nodeOrientationRtl" text="%preferences.general.interfaceOrientation.rtl" alignment="CENTER_RIGHT" toggleGroup="${nodeOrientation}"/>
|
||||
</HBox>
|
||||
|
||||
<CheckBox fx:id="startHiddenCheckbox" text="%preferences.general.startHidden" visible="${controller.trayMenuSupported}" managed="${controller.trayMenuSupported}"/>
|
||||
<CheckBox fx:id="showMinimizeButtonCheckbox" text="%preferences.general.showMinimizeButton" visible="${controller.trayMenuInitialized}" managed="${controller.trayMenuInitialized}"/>
|
||||
|
||||
<CheckBox fx:id="showTrayIconCheckbox" text="%preferences.general.showTrayIcon" visible="${controller.trayMenuSupported}" managed="${controller.trayMenuSupported}"/>
|
||||
|
||||
<CheckBox fx:id="startHiddenCheckbox" text="%preferences.general.startHidden" />
|
||||
|
||||
<HBox spacing="6" alignment="CENTER_LEFT">
|
||||
<CheckBox fx:id="debugModeCheckbox" text="%preferences.general.debugLogging"/>
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.Arc?>
|
||||
<?import org.cryptomator.ui.stats.SmoothAreaChart?>
|
||||
<HBox xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
fx:controller="org.cryptomator.ui.stats.VaultStatisticsController"
|
||||
@@ -38,7 +39,7 @@
|
||||
<!-- Read -->
|
||||
<VBox prefWidth="300" prefHeight="300" spacing="6" alignment="CENTER">
|
||||
<ThrougputLabel styleClass="label-large" idleFormat="%stats.read.throughput.idle" kibsFormat="%stats.read.throughput.kibs" mibsFormat="%stats.read.throughput.mibs" bytesPerSecond="${controller.bpsRead}"/>
|
||||
<AreaChart fx:id="readChart" styleClass="io-stats" createSymbols="false" animated="false">
|
||||
<SmoothAreaChart fx:id="readChart" styleClass="io-stats" createSymbols="false" animated="false">
|
||||
<xAxis>
|
||||
<NumberAxis fx:id="readChartXAxis" styleClass="io-stats" autoRanging="false" forceZeroInRange="false" side="BOTTOM"/>
|
||||
</xAxis>
|
||||
@@ -48,7 +49,7 @@
|
||||
<cursor>
|
||||
<Cursor fx:constant="DEFAULT"/>
|
||||
</cursor>
|
||||
</AreaChart>
|
||||
</SmoothAreaChart>
|
||||
<DataLabel byteFormat="%stats.read.total.data.none" kibFormat="%stats.read.total.data.kib" mibFormat="%stats.read.total.data.mib" gibFormat="%stats.read.total.data.gib" dataInBytes="${controller.totalBytesRead}"/>
|
||||
<DataLabel byteFormat="%stats.decr.total.data.none" kibFormat="%stats.decr.total.data.kib" mibFormat="%stats.decr.total.data.mib" gibFormat="%stats.decr.total.data.gib" dataInBytes="${controller.totalBytesDecrypted}"/>
|
||||
<FormattedLabel format="%stats.read.accessCount" arg1="${controller.filesRead}"/>
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.Hyperlink?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
@@ -25,18 +24,20 @@
|
||||
<FontAwesome5IconView glyph="KEY" glyphSize="15"/>
|
||||
</graphic>
|
||||
</Button>
|
||||
<Hyperlink text="%main.vaultDetail.optionsBtn" onAction="#showVaultOptions">
|
||||
<Hyperlink text="%main.vaultDetail.passwordSavedInKeychain" visible="${controller.passwordSaved}" onAction="#showKeyVaultOptions">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="COG"/>
|
||||
<FontAwesome5IconView glyph="LOCK"/>
|
||||
</graphic>
|
||||
</Hyperlink>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS"/>
|
||||
<HBox alignment="CENTER_RIGHT" spacing="6">
|
||||
<Label styleClass="label-small,label-muted" text="%main.vaultDetail.passwordSavedInKeychain" visible="${controller.passwordSaved}">
|
||||
|
||||
<HBox alignment="BOTTOM_RIGHT">
|
||||
<Button text="%main.vaultDetail.optionsBtn" minWidth="120" onAction="#showVaultOptions">
|
||||
<graphic>
|
||||
<FontAwesome5IconView styleClass="glyph-icon-muted" glyph="LOCK"/>
|
||||
<FontAwesome5IconView glyph="COG"/>
|
||||
</graphic>
|
||||
</Label>
|
||||
</Button>
|
||||
</HBox>
|
||||
</children>
|
||||
</VBox>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
tabClosingPolicy="UNAVAILABLE"
|
||||
tabDragPolicy="FIXED">
|
||||
<tabs>
|
||||
<Tab fx:id="generalTab" text="%vaultOptions.general">
|
||||
<Tab fx:id="generalTab" id="GENERAL" text="%vaultOptions.general">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="WRENCH"/>
|
||||
</graphic>
|
||||
@@ -20,7 +20,7 @@
|
||||
<fx:include source="/fxml/vault_options_general.fxml"/>
|
||||
</content>
|
||||
</Tab>
|
||||
<Tab fx:id="mountTab" text="%vaultOptions.mount">
|
||||
<Tab fx:id="mountTab" id="MOUNT" text="%vaultOptions.mount">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="HDD"/>
|
||||
</graphic>
|
||||
@@ -28,7 +28,7 @@
|
||||
<fx:include source="/fxml/vault_options_mount.fxml"/>
|
||||
</content>
|
||||
</Tab>
|
||||
<Tab fx:id="keyTab" text="%vaultOptions.masterkey">
|
||||
<Tab fx:id="keyTab" id="KEY" text="%vaultOptions.masterkey">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="KEY"/>
|
||||
</graphic>
|
||||
|
||||
@@ -96,7 +96,7 @@ forgetPassword.confirmBtn=Forget Password
|
||||
# Unlock
|
||||
unlock.title=Unlock Vault
|
||||
unlock.passwordPrompt=Enter password for "%s":
|
||||
unlock.savePassword=Save Password
|
||||
unlock.savePassword=Remember Password
|
||||
unlock.unlockBtn=Unlock
|
||||
## Success
|
||||
unlock.success.message=Unlocked "%s" successfully! Your vault is now accessible.
|
||||
@@ -150,6 +150,8 @@ preferences.general.theme.automatic=Automatic
|
||||
preferences.general.theme.light=Light
|
||||
preferences.general.theme.dark=Dark
|
||||
preferences.general.unlockThemes=Unlock dark mode
|
||||
preferences.general.showMinimizeButton=Show minimize button
|
||||
preferences.general.showTrayIcon=Show tray icon (requires restart)
|
||||
preferences.general.startHidden=Hide window when starting Cryptomator
|
||||
preferences.general.debugLogging=Enable debug logging
|
||||
preferences.general.debugDirectory=Reveal log files
|
||||
@@ -201,7 +203,7 @@ stats.read.accessCount=Total reads: %d
|
||||
stats.write.throughput.idle=Write: idle
|
||||
stats.write.throughput.kibs=Write: %.2f kiB/s
|
||||
stats.write.throughput.mibs=Write: %.2f MiB/s
|
||||
stats.write.total.data.none=Data read: -
|
||||
stats.write.total.data.none=Data written: -
|
||||
stats.write.total.data.kib=Data written: %.1f kiB
|
||||
stats.write.total.data.mib=Data written: %.1f MiB
|
||||
stats.write.total.data.gib=Data written: %.1f GiB
|
||||
|
||||
@@ -95,20 +95,22 @@ forgetPassword.confirmBtn=نسيت كلمة المرور
|
||||
# Unlock
|
||||
unlock.title=افتح الحافظة
|
||||
unlock.passwordPrompt=أدخل كلمة السر لـ "%s":
|
||||
unlock.savePassword=احفظ كلمة المرور
|
||||
unlock.unlockBtn=افتح
|
||||
## Success
|
||||
unlock.success.message=تم فتح المخزن "%s" بنجاح! يمكنك الوصول إليه الآن.
|
||||
unlock.success.rememberChoice=تذكر اختياري ولا تظهر هذا مرة أخرى
|
||||
unlock.success.revealBtn=افتح الحافظة
|
||||
## Failure
|
||||
unlock.error.heading=غير قادر على فتح الخزنة
|
||||
### Invalid Mount Point
|
||||
unlock.error.invalidMountPoint.notExisting=نقطة التحميل ليست مجلد فارغ أو غير موجودة: %s
|
||||
unlock.error.invalidMountPoint.existing=نقطة/مجلد التحميل موجود بالفعل أو المجلد الأصل مفقود: %s
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
lock.forced.confirmBtn=فرض القفل
|
||||
## Failure
|
||||
lock.fail.heading=فشلت عملية اقفال الخزنة.
|
||||
|
||||
# Migration
|
||||
migration.title=ترقية الحافظة
|
||||
@@ -175,8 +177,12 @@ preferences.donationKey.getDonationKey=الحصول على مفتاح تبرع
|
||||
preferences.about=حول البرنامج
|
||||
|
||||
# Vault Statistics
|
||||
stats.cacheHitRate=معدل استخدام الكاش
|
||||
## Read
|
||||
stats.read.throughput.idle=قراءة: خامل
|
||||
stats.decr.total.data.none=تم فك تشفير البيانات:-
|
||||
## Write
|
||||
stats.encr.total.data.none=البيانات المشفرة: -
|
||||
|
||||
# Main Window
|
||||
main.closeBtn.tooltip=إغلاق
|
||||
@@ -206,9 +212,11 @@ main.vaultDetail.accessLocation=يمكن الوصول إلى محتويات مخ
|
||||
main.vaultDetail.revealBtn=اظهار القرص
|
||||
main.vaultDetail.lockBtn=قفل
|
||||
main.vaultDetail.bytesPerSecondRead=قراءة:
|
||||
main.vaultDetail.bytesPerSecondWritten=كتابة:
|
||||
main.vaultDetail.throughput.idle=خمول
|
||||
main.vaultDetail.throughput.kbps=%.1f كيلوبايت/ث
|
||||
main.vaultDetail.throughput.mbps=%.1f ميجابايت/ث
|
||||
main.vaultDetail.stats=إحصائيات الخزنة
|
||||
### Missing
|
||||
main.vaultDetail.missing.info=لم يتمكن Cryptomator من العثور على خزنة في هذا المسار.
|
||||
main.vaultDetail.missing.recheck=إعادة الفحص
|
||||
|
||||
@@ -95,7 +95,6 @@ forgetPassword.confirmBtn=Zaboravili ste šifru
|
||||
# Unlock
|
||||
unlock.title=Otključaj sef
|
||||
unlock.passwordPrompt=Unesite lozinku za "%s":
|
||||
unlock.savePassword=Snimi lozinku
|
||||
unlock.unlockBtn=Otključaj
|
||||
## Success
|
||||
unlock.success.message=Uspješno ste otključali "%s"! Vaš sef je sada dostupan.
|
||||
@@ -105,61 +104,214 @@ unlock.success.revealBtn=Otkrij sef
|
||||
unlock.error.heading=Sef nije moguće otključati
|
||||
### Invalid Mount Point
|
||||
unlock.error.invalidMountPoint.notExisting=Tačka postavljanja "%s" nije direktorij, nije prazna ili ne postoji.
|
||||
unlock.error.invalidMountPoint.existing=Tačka povezivanja "%s" već postoji ili nadređeni folder nedostaje.
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
lock.forced.heading=Zaključavanje nije uspjelo
|
||||
lock.forced.message=Zaključavanje "%s" blokirano je operacijama na čekanju ili otvorenim datotekama. Možete prisilno zaključati ovaj sef, međutim prekid U / I-a može rezultirati gubitkom nespremljenih podataka.
|
||||
lock.forced.confirmBtn=Prisilno zaključaj
|
||||
## Failure
|
||||
lock.fail.heading=Zaključavanje sefa nije uspjelo.
|
||||
lock.fail.message=Sef "%s" nije moguće zaključati. Osigurajte da je nespremljeni rad sačuvan negdje drugdje i da su važne operacije čitanja / pisanja završene. Da biste zatvorili sef, zaustavite Cryptomator proces.
|
||||
|
||||
# Migration
|
||||
migration.title=Nadogradi sef
|
||||
## Start
|
||||
migration.start.prompt=Sef "%s" treba ažurirati na noviji format. Prije nastavka, provjerite da nije na čekanju sinkronizacija koja utječe na ovaj sef.
|
||||
migration.start.confirm=Da, moj sef je u potpunosti sinhroniziran
|
||||
## Run
|
||||
migration.run.enterPassword=Unesite lozinku za "%s"
|
||||
migration.run.startMigrationBtn=Nadogradi sef
|
||||
migration.run.progressHint=Ovo bi moglo potrajati…
|
||||
## Sucess
|
||||
migration.success.nextStepsInstructions="%s" je uspješno nadograđen.\nSada možete otključati svoj sef.
|
||||
migration.success.unlockNow=Otključaj sada
|
||||
## Missing file system capabilities
|
||||
migration.error.missingFileSystemCapabilities.title=Nepodržan tip datoteke
|
||||
migration.error.missingFileSystemCapabilities.description=Migracija nije započeta, jer se vaš sef nalazi u neadekvatnom sistemu datoteka.
|
||||
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=Sistem datoteka ne podržava duga imena datoteka.
|
||||
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=Sistem datoteka ne podržava duga imena datoteka.
|
||||
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=Sistem datoteka ne dozvoljava čitanje.
|
||||
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=Sistem datoteka ne dozvoljava pisanje.
|
||||
## Impossible
|
||||
migration.impossible.heading=Sef se ne može nadograditi
|
||||
migration.impossible.reason=Sef se ne može automatski migrirati jer njegovo mjesto za pohranu ili pristupna točka nisu kompatibilni.
|
||||
migration.impossible.moreInfo=Sef se i dalje može otvoriti sa starijom verzijom. Za upute o ručnom migriranju sefa posjetite
|
||||
|
||||
# Preferences
|
||||
preferences.title=Postavke
|
||||
## General
|
||||
preferences.general=Generalno
|
||||
preferences.general.theme=Izgled
|
||||
preferences.general.theme.automatic=Automatski
|
||||
preferences.general.theme.light=Svijetlo
|
||||
preferences.general.theme.dark=Tamno
|
||||
preferences.general.unlockThemes=Otključaj tamni mod
|
||||
preferences.general.showMinimizeButton=Pokaži dugme za minimiziranje
|
||||
preferences.general.showTrayIcon=Prikaži tray ikonu (potrebnan restart)
|
||||
preferences.general.startHidden=Sakrij prozor prilikom pokretanja Cryptomatora
|
||||
preferences.general.debugLogging=Omogući evidenciju otklanjanja pogrešaka
|
||||
preferences.general.debugDirectory=Pokaži dnevnik podataka
|
||||
preferences.general.autoStart=Pokreni Cryptomator pri pokretanju sistema
|
||||
preferences.general.keychainBackend=Pohrani lozinku sa
|
||||
preferences.general.keychainBackend.org.cryptomator.linux.keychain.SecretServiceKeychainAccess=Gnome Keyring
|
||||
preferences.general.keychainBackend.org.cryptomator.linux.keychain.KDEWalletKeychainAccess=KDE Wallet
|
||||
preferences.general.keychainBackend.org.cryptomator.macos.keychain.MacSystemKeychainAccess=macOS Keychain Access
|
||||
preferences.general.keychainBackend.org.cryptomator.windows.keychain.WindowsProtectedKeychainAccess=Windows Data Protection
|
||||
preferences.general.interfaceOrientation=Orijentacija Interfejsa
|
||||
preferences.general.interfaceOrientation.ltr=S lijeva ka desno
|
||||
preferences.general.interfaceOrientation.rtl=Sa desna ka lijevo
|
||||
## Volume
|
||||
preferences.volume=Virtuelni pogon
|
||||
preferences.volume.type=Tip volumena
|
||||
preferences.volume.webdav.port=WebDAV Port
|
||||
preferences.volume.webdav.scheme=WebDAV Scheme
|
||||
## Updates
|
||||
preferences.updates=Ažuriranja
|
||||
preferences.updates.currentVersion=Trenutna verzija: %s
|
||||
preferences.updates.autoUpdateCheck=Automatski provjeri ima li ažuriranja
|
||||
preferences.updates.checkNowBtn=Provjeri sada
|
||||
preferences.updates.updateAvailable=Dostupno ažuriranje na verziju %s.
|
||||
## Donation Key
|
||||
preferences.donationKey=Donacija
|
||||
preferences.donationKey.registeredFor=Registrovan za %s
|
||||
preferences.donationKey.noDonationKey=Nije pronađen važeći ključ za donaciju. To je poput licence, ali za sjajne ljude koji koriste besplatni softver. ;-)
|
||||
preferences.donationKey.getDonationKey=Nabavite ključ za donaciju
|
||||
## About
|
||||
preferences.about=O programu
|
||||
|
||||
# Vault Statistics
|
||||
stats.title=Statistika za %s
|
||||
stats.cacheHitRate=Brzina učitavanja u predmemoriju
|
||||
## Read
|
||||
stats.read.throughput.idle=Čitaj: U pripravnosti
|
||||
stats.read.throughput.kibs=Čitanje: %.2f kiB/s
|
||||
stats.read.throughput.mibs=Čitanje: %.2f MiB/s
|
||||
stats.read.total.data.none=Pročitano podataka: -
|
||||
stats.read.total.data.kib=Pročitano podataka: %.1f kiB
|
||||
stats.read.total.data.mib=Pročitano podataka: %.1f MiB
|
||||
stats.read.total.data.gib=Pročitano podataka: %.1f GiB
|
||||
stats.decr.total.data.none=Otključani podaci: -
|
||||
stats.decr.total.data.kib=Otključano podataka: %.1f kiB
|
||||
stats.decr.total.data.mib=Otključano podataka: %.1f MiB
|
||||
stats.decr.total.data.gib=Otključano podataka: %.1f GiB
|
||||
stats.read.accessCount=Ukupno pročitano: %d
|
||||
## Write
|
||||
stats.write.throughput.idle=Pisanje: U pripravnosti
|
||||
stats.write.throughput.kibs=Upisano: %.2f kiB/s
|
||||
stats.write.throughput.mibs=Upisano: %.2f MiB/s
|
||||
stats.write.total.data.none=Podaci su upisani:-
|
||||
stats.write.total.data.kib=Upisano podataka: %.1f kiB
|
||||
stats.write.total.data.mib=Upisano podataka: %.1f MiB
|
||||
stats.write.total.data.gib=Upisano podataka: %.1f GiB
|
||||
stats.encr.total.data.none=Otključano podataka: -
|
||||
stats.encr.total.data.kib=Otključano podataka: %.1f kiB
|
||||
stats.encr.total.data.mib=Otključano podataka: %.1f MiB
|
||||
stats.encr.total.data.gib=Otključano podataka: %.1f GiB
|
||||
stats.write.accessCount=Ukupno upisano: %d
|
||||
|
||||
# Main Window
|
||||
main.closeBtn.tooltip=Zatvori
|
||||
main.minimizeBtn.tooltip=Minimiziraj
|
||||
main.preferencesBtn.tooltip=Postavke
|
||||
main.debugModeEnabled.tooltip=Omogućen je mod otklanjanja pogrešaka
|
||||
main.donationKeyMissing.tooltip=Molimo razmislite o doniranju
|
||||
## Drag 'n' Drop
|
||||
main.dropZone.dropVault=Dodajte ovaj sef
|
||||
main.dropZone.unknownDragboardContent=Ako želite dodati sef, povucite ga u ovaj prozor
|
||||
## Vault List
|
||||
main.vaultlist.emptyList.onboardingInstruction=Kliknite ovdje da dodate sef
|
||||
main.vaultlist.contextMenu.remove=Ukloni Sef…
|
||||
main.vaultlist.addVaultBtn=Dodaj sef
|
||||
## Vault Detail
|
||||
### Welcome
|
||||
main.vaultDetail.welcomeOnboarding=Hvala što ste izabrali Cryptomator za zaštitu podataka. Ako vam je potrebna pomoć, pogledajte naše vodiče za početak:
|
||||
### Locked
|
||||
main.vaultDetail.lockedStatus=ZAKLJUČANO
|
||||
main.vaultDetail.unlockBtn=Otključaj…
|
||||
main.vaultDetail.unlockNowBtn=Otključaj sada
|
||||
main.vaultDetail.optionsBtn=Opcije sefa
|
||||
main.vaultDetail.passwordSavedInKeychain=Šifra sačuvana
|
||||
### Unlocked
|
||||
main.vaultDetail.unlockedStatus=OTKLJUČANO
|
||||
main.vaultDetail.accessLocation=Sadržaj Vašeg sefa je dostupan ovdje:
|
||||
main.vaultDetail.revealBtn=Otkrij pogon
|
||||
main.vaultDetail.lockBtn=Zaključaj
|
||||
main.vaultDetail.bytesPerSecondRead=Čitaj:
|
||||
main.vaultDetail.bytesPerSecondWritten=Piši:
|
||||
main.vaultDetail.throughput.idle=u stanju mirovanja
|
||||
main.vaultDetail.throughput.kbps=%.1f kiB/s
|
||||
main.vaultDetail.throughput.mbps=%.1f MiB/s
|
||||
main.vaultDetail.stats=Statistika sefa
|
||||
### Missing
|
||||
main.vaultDetail.missing.info=Cryptomator nije mogao pronaći disk na ovoj lokaciji.
|
||||
main.vaultDetail.missing.recheck=Provjeri ponovo
|
||||
main.vaultDetail.missing.remove=Ukloni sa liste sefova…
|
||||
main.vaultDetail.missing.changeLocation=Promijeni lokaciju sefa…
|
||||
### Needs Migration
|
||||
main.vaultDetail.migrateButton=Nadogradi sef
|
||||
main.vaultDetail.migratePrompt=Da biste mogli pristupiti svom sefu, morate ga nadograditi na novi format
|
||||
|
||||
# Wrong File Alert
|
||||
wrongFileAlert.title=Kako enkriptovati podatke
|
||||
wrongFileAlert.header.title=Da li ste pokušali enkriptovati ove datoteke?
|
||||
wrongFileAlert.header.lead=U tu svrhu Cryptomator kreira volumen u vašem upravljačkom sistemu.
|
||||
wrongFileAlert.instruction.0=Da biste enkriptovali datoteke, slijedite ove korake:
|
||||
wrongFileAlert.instruction.1=1. Otključajte sef.
|
||||
wrongFileAlert.instruction.2=2. Kliknite "Otkrivanje" da biste otvorili volumen u vašem upravitelju datotekama.
|
||||
wrongFileAlert.instruction.3=3. Dodajte datoteke u ovaj disk.
|
||||
wrongFileAlert.link=Za dalju podršku, posjetite
|
||||
|
||||
# Vault Options
|
||||
## General
|
||||
vaultOptions.general=Generalno
|
||||
vaultOptions.general.vaultName=Ime sefa
|
||||
vaultOptions.general.unlockAfterStartup=Otključaj sef pri pokretanju Cryptomatora
|
||||
vaultOptions.general.actionAfterUnlock=Nakon uspješnog otključavanja
|
||||
vaultOptions.general.actionAfterUnlock.ignore=Ne radi ništa
|
||||
vaultOptions.general.actionAfterUnlock.reveal=Otkrij pogon
|
||||
vaultOptions.general.actionAfterUnlock.ask=Pitaj
|
||||
## Mount
|
||||
vaultOptions.mount=Povezivanje
|
||||
vaultOptions.mount.readonly=Samo čitanje
|
||||
vaultOptions.mount.customMountFlags=Prilagođena obilježja povezivanja
|
||||
vaultOptions.mount.winDriveLetterOccupied=zauzeto
|
||||
vaultOptions.mount.mountPoint=Tačka povezivanja
|
||||
vaultOptions.mount.mountPoint.auto=Automatski odaberi pogodnu lokaciju
|
||||
vaultOptions.mount.mountPoint.driveLetter=Koristi dodjeljeno slovo (oznaku) diska
|
||||
vaultOptions.mount.mountPoint.custom=Prilagođena adresa
|
||||
vaultOptions.mount.mountPoint.directoryPickerButton=Odaberi…
|
||||
vaultOptions.mount.mountPoint.directoryPickerTitle=Izaberi praznu mapu
|
||||
## Master Key
|
||||
vaultOptions.masterkey=Šifra
|
||||
vaultOptions.masterkey.changePasswordBtn=Promjeni lozinku
|
||||
vaultOptions.masterkey.forgetSavedPasswordBtn=Zaborav spremljenu šifru
|
||||
vaultOptions.masterkey.recoveryKeyExpanation=Ključ za oporavak je vaše jedino sredstvo za vraćanje pristupa sefu ako izgubite lozinku.
|
||||
vaultOptions.masterkey.showRecoveryKeyBtn=Pokaži ključ za oporavak
|
||||
vaultOptions.masterkey.recoverPasswordBtn=Povrati šifru
|
||||
|
||||
# Recovery Key
|
||||
recoveryKey.title=Ključ za oporavak
|
||||
recoveryKey.enterPassword.prompt=Unesite šifru da biste prikazali ključ za oporavak za "%s":
|
||||
recoveryKey.display.message=Sljedeći ključ za oporavak može se koristiti za vraćanje pristupa "%s":
|
||||
recoveryKey.display.StorageHints=Pohranite ga negdje vrlo sigurno, npr.:\n • Spremite ga pomoću menadžera lozinki\n • Spremite ga na USB disk\n • Odštampajte ga na papiru
|
||||
recoveryKey.recover.prompt=Unesite ključ za oporavak za "%s":
|
||||
recoveryKey.recover.validKey=Ključ za oporavak je ispravan
|
||||
recoveryKey.printout.heading=Cryptomator Ključ za oporavak za \n"%s"\n
|
||||
|
||||
# New Password
|
||||
newPassword.promptText=Unesi novu šifru
|
||||
newPassword.reenterPassword=Potvrdi novu šifru
|
||||
newPassword.passwordsMatch=Šifra odgovara!
|
||||
newPassword.passwordsDoNotMatch=Šifre se ne poklapaju
|
||||
passwordStrength.messageLabel.tooShort=Upotrijebite najmanje %d znakova
|
||||
passwordStrength.messageLabel.0=Veoma slabo
|
||||
passwordStrength.messageLabel.1=Slabo
|
||||
passwordStrength.messageLabel.2=Dovoljno
|
||||
passwordStrength.messageLabel.3=Sigurno
|
||||
passwordStrength.messageLabel.4=Veoma sigurno
|
||||
|
||||
# Quit
|
||||
quit.prompt=Zatvoriti prijavu? Postoje otključani sefovi.
|
||||
quit.lockAndQuit=Zaključaj i zatvori
|
||||
|
||||
@@ -109,6 +109,7 @@ unlock.error.invalidMountPoint.existing=El punt de muntatge o la carpeta ja exis
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
lock.forced.heading=Ha fallat el blocatge
|
||||
lock.forced.message=No s'ha blocat "%s" perquè hi ha operacions pendents o fitxers oberts. Podeu forçar-ne el blocatge però heu de saber que interrompre l'entrada/sortida pot produir la pèrdua de dades.
|
||||
lock.forced.confirmBtn=Força el blocatge
|
||||
## Failure
|
||||
@@ -148,6 +149,8 @@ preferences.general.theme.automatic=Automàtic
|
||||
preferences.general.theme.light=Clar
|
||||
preferences.general.theme.dark=Fosc
|
||||
preferences.general.unlockThemes=Desbloqueja el tema fosc
|
||||
preferences.general.showMinimizeButton=Mostra el botó de minimitzar
|
||||
preferences.general.showTrayIcon=Mostra la icona en la barra (cal reiniciar)
|
||||
preferences.general.startHidden=Amaga la finestra quan s'inicia Cryptomator
|
||||
preferences.general.debugLogging=Habilita el registre de depuració
|
||||
preferences.general.debugDirectory=Mostra els fitxers de registres
|
||||
@@ -156,6 +159,7 @@ preferences.general.keychainBackend=Desar contrasenyes amb
|
||||
preferences.general.keychainBackend.org.cryptomator.linux.keychain.SecretServiceKeychainAccess=Anell de claus de Gnome
|
||||
preferences.general.keychainBackend.org.cryptomator.linux.keychain.KDEWalletKeychainAccess=Cartera de KDE
|
||||
preferences.general.keychainBackend.org.cryptomator.macos.keychain.MacSystemKeychainAccess=Accés a clauers macOS
|
||||
preferences.general.keychainBackend.org.cryptomator.windows.keychain.WindowsProtectedKeychainAccess=Windows Data Protection
|
||||
preferences.general.interfaceOrientation=Orientació de la interfície
|
||||
preferences.general.interfaceOrientation.ltr=Esquerra a dreta
|
||||
preferences.general.interfaceOrientation.rtl=Dreta a esquerra
|
||||
@@ -180,6 +184,7 @@ preferences.about=Quant a
|
||||
|
||||
# Vault Statistics
|
||||
stats.title=Estadístiques per a %s
|
||||
stats.cacheHitRate=Relació d'encerts de la memòria cau
|
||||
## Read
|
||||
stats.read.throughput.idle=Llegit: inactiu
|
||||
stats.read.throughput.kibs=Llegit: %.2f kiB/s
|
||||
@@ -197,7 +202,7 @@ stats.read.accessCount=Lectures en total: %d
|
||||
stats.write.throughput.idle=Escriu: inactiu
|
||||
stats.write.throughput.kibs=Escriu: %.2f kiB/s
|
||||
stats.write.throughput.mibs=Escriu: %.2f MiB/s
|
||||
stats.write.total.data.none=Dades llegides: -
|
||||
stats.write.total.data.none=Dades escrites
|
||||
stats.write.total.data.kib=Dades escrites: %.1f kiB
|
||||
stats.write.total.data.mib=Dades escrites: %.1f MiB
|
||||
stats.write.total.data.gib=Dades escrites: %.1f GiB
|
||||
|
||||
@@ -95,7 +95,7 @@ forgetPassword.confirmBtn=Zapomenout heslo
|
||||
# Unlock
|
||||
unlock.title=Odemknout trezor
|
||||
unlock.passwordPrompt=Zadejte heslo pro "%s":
|
||||
unlock.savePassword=Uložit heslo
|
||||
unlock.savePassword=Zapamatovat heslo
|
||||
unlock.unlockBtn=Odemknout
|
||||
## Success
|
||||
unlock.success.message=Trezor "%s" byl úspěšně odemčen a nyní je dostupný.
|
||||
@@ -144,6 +144,8 @@ preferences.general.theme.automatic=Automaticky
|
||||
preferences.general.theme.light=Světlý
|
||||
preferences.general.theme.dark=Tmavý
|
||||
preferences.general.unlockThemes=Odemknout tmavý režim
|
||||
preferences.general.showMinimizeButton=Zobrazit tlačítko minimalizovat
|
||||
preferences.general.showTrayIcon=Zobrazit ikonu v liště (vyžaduje restart)
|
||||
preferences.general.startHidden=Skrýt okno Cryptomatoru při spuštění
|
||||
preferences.general.debugLogging=Ladicí režim
|
||||
preferences.general.debugDirectory=Ukázat soubory se záznamy událostí (log)
|
||||
@@ -195,7 +197,7 @@ stats.read.accessCount=Celkem přečteno: %d
|
||||
stats.write.throughput.idle=Zápis: nečinný
|
||||
stats.write.throughput.kibs=Zápis: %.2f kiB/s
|
||||
stats.write.throughput.mibs=Zápis: %.2f MiB/s
|
||||
stats.write.total.data.none=Přečteno: -
|
||||
stats.write.total.data.none=Zapsaná data: -
|
||||
stats.write.total.data.kib=Zapsáno: %.1f kiB
|
||||
stats.write.total.data.mib=Zapsáno: %.1f MiB
|
||||
stats.write.total.data.gib=Zapsáno: %.1f GiB
|
||||
|
||||
@@ -95,7 +95,7 @@ forgetPassword.confirmBtn=Passwort vergessen
|
||||
# Unlock
|
||||
unlock.title=Tresor entsperren
|
||||
unlock.passwordPrompt=Gib das Passwort für „%s“ ein:
|
||||
unlock.savePassword=Passwort speichern
|
||||
unlock.savePassword=Passwort merken
|
||||
unlock.unlockBtn=Entsperren
|
||||
## Success
|
||||
unlock.success.message=„%s“ erfolgreich entsperrt! Nun kannst du auf deinen Tresor zugreifen.
|
||||
@@ -109,11 +109,11 @@ unlock.error.invalidMountPoint.existing=Einhängepunkt/Ordner bereits vorhanden
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
lock.forced.heading=Tresor konnte nicht kontrolliert gesperrt werden
|
||||
lock.forced.message=Das Sperren von „%s“ wurde durch noch ablaufende Vorgänge oder offene Dateien verhindert. Sie können das Sperren dieses Tresors erzwingen, allerdings kann dies zum Verlust ungespeicherter Daten führen.
|
||||
lock.forced.heading=Sperren fehlgeschlagen
|
||||
lock.forced.message=Aufgrund von Zugriffen laufender Prozesse oder geöffneter Dateien konnte „%s“ nicht gesperrt werden. Du kannst das Sperren dieses Tresors erzwingen, allerdings kann dies zum Verlust ungespeicherter Daten führen.
|
||||
lock.forced.confirmBtn=Sperren erzwingen
|
||||
## Failure
|
||||
lock.fail.heading=Der Tresor konnte nicht gesperrt werden.
|
||||
lock.fail.heading=Tresor konnte nicht gesperrt werden.
|
||||
lock.fail.message=Der Tresor „%s“ konnte nicht gesperrt werden. Stellen Sie sicher, dass Sie Ihre ungespeicherten Arbeit an anderer Stelle speichern und wichtige Lese-/Schreibvorgänge abgeschlossen sind. Um den Tresor zu schließen, beenden Sie den Cryptomator-Prozess.
|
||||
|
||||
# Migration
|
||||
@@ -149,6 +149,8 @@ preferences.general.theme.automatic=Automatisch
|
||||
preferences.general.theme.light=Hell
|
||||
preferences.general.theme.dark=Dunkel
|
||||
preferences.general.unlockThemes=Dunklen Modus freischalten
|
||||
preferences.general.showMinimizeButton=Minimieren-Schaltfläche anzeigen
|
||||
preferences.general.showTrayIcon=Symbol im Infobereich anzeigen (Neustart erforderlich)
|
||||
preferences.general.startHidden=Cryptomator im Hintergrund starten
|
||||
preferences.general.debugLogging=Diagnoseprotokoll aktivieren
|
||||
preferences.general.debugDirectory=Protokolldateien anzeigen
|
||||
@@ -187,28 +189,28 @@ stats.cacheHitRate=Cache-Trefferrate
|
||||
stats.read.throughput.idle=Lesen: Leerlauf
|
||||
stats.read.throughput.kibs=Lesen: %.2f kiB/s
|
||||
stats.read.throughput.mibs=Lesen: %.2f MiB/s
|
||||
stats.read.total.data.none=Daten gelesen: -
|
||||
stats.read.total.data.kib=Daten gelesen: %.1f kiB
|
||||
stats.read.total.data.mib=Daten gelesen: %.1f MiB
|
||||
stats.read.total.data.gib=Daten gelesen: %.1f GiB
|
||||
stats.decr.total.data.none=Daten entschlüsselt: -
|
||||
stats.decr.total.data.kib=Daten entschlüsselt: %.1f kiB
|
||||
stats.decr.total.data.mib=Daten entschlüsselt: %.1f MiB
|
||||
stats.decr.total.data.gib=Daten entschlüsselt: %.1f GiB
|
||||
stats.read.accessCount=Gesamt gelesen: %d
|
||||
stats.read.total.data.none=Gelesen: -
|
||||
stats.read.total.data.kib=Gelesen: %.1f kiB
|
||||
stats.read.total.data.mib=Gelesen: %.1f MiB
|
||||
stats.read.total.data.gib=Gelesen: %.1f GiB
|
||||
stats.decr.total.data.none=Entschlüsselt: -
|
||||
stats.decr.total.data.kib=Entschlüsselt: %.1f kiB
|
||||
stats.decr.total.data.mib=Entschlüsselt: %.1f MiB
|
||||
stats.decr.total.data.gib=Entschlüsselt: %.1f GiB
|
||||
stats.read.accessCount=Lesezugriffe: %d
|
||||
## Write
|
||||
stats.write.throughput.idle=Schreiben: Leerlauf
|
||||
stats.write.throughput.kibs=Schreiben: %.2f kiB/s
|
||||
stats.write.throughput.mibs=Schreiben: %.2f MiB/s
|
||||
stats.write.total.data.none=Daten gelesen: -
|
||||
stats.write.total.data.kib=Daten geschrieben: %.1f kiB
|
||||
stats.write.total.data.mib=Daten geschrieben: %.1f MiB
|
||||
stats.write.total.data.gib=Daten geschrieben: %.1f GiB
|
||||
stats.encr.total.data.none=Daten verschlüsselt: -
|
||||
stats.encr.total.data.kib=Daten verschlüsselt: %.1f kiB
|
||||
stats.encr.total.data.mib=Datenverschlüsselt: %.1f MiB
|
||||
stats.encr.total.data.gib=Daten verschlüsselt: %.1f GiB
|
||||
stats.write.accessCount=Gesamt geschrieben: %d
|
||||
stats.write.total.data.none=Geschrieben: -
|
||||
stats.write.total.data.kib=Geschrieben: %.1f kiB
|
||||
stats.write.total.data.mib=Geschrieben: %.1f MiB
|
||||
stats.write.total.data.gib=Geschrieben: %.1f GiB
|
||||
stats.encr.total.data.none=Verschlüsselt: -
|
||||
stats.encr.total.data.kib=Verschlüsselt: %.1f kiB
|
||||
stats.encr.total.data.mib=Verschlüsselt: %.1f MiB
|
||||
stats.encr.total.data.gib=Verschlüsselt: %.1f GiB
|
||||
stats.write.accessCount=Schreibzugriffe: %d
|
||||
|
||||
# Main Window
|
||||
main.closeBtn.tooltip=Schließen
|
||||
@@ -284,7 +286,7 @@ vaultOptions.mount.mountPoint.directoryPickerButton=Durchsuchen …
|
||||
vaultOptions.mount.mountPoint.directoryPickerTitle=Wähle ein leeres Verzeichnis
|
||||
## Master Key
|
||||
vaultOptions.masterkey=Passwort
|
||||
vaultOptions.masterkey.changePasswordBtn=Password ändern
|
||||
vaultOptions.masterkey.changePasswordBtn=Passwort ändern
|
||||
vaultOptions.masterkey.forgetSavedPasswordBtn=Gespeichertes Passwort vergessen
|
||||
vaultOptions.masterkey.recoveryKeyExpanation=Bei Verlust deines Passworts ist ein Wiederherstellungsschlüssel deine einzige Möglichkeit, den Zugriff auf einen Tresor wiederherzustellen.
|
||||
vaultOptions.masterkey.showRecoveryKeyBtn=Wiederherstellungsschlüssel anzeigen
|
||||
|
||||
@@ -95,7 +95,7 @@ forgetPassword.confirmBtn=Ξέχασα τον κωδικό πρόσβασης
|
||||
# Unlock
|
||||
unlock.title=Ξεκλείδωμα Vault
|
||||
unlock.passwordPrompt=Εισάγετε τον κωδικό για "%s":
|
||||
unlock.savePassword=Αποθήκευση κωδικού
|
||||
unlock.savePassword=Απομνημόνευση κωδικού πρόσβασης
|
||||
unlock.unlockBtn=Ξεκλείδωμα
|
||||
## Success
|
||||
unlock.success.message="%s" ξεκλειδώθηκε επιτυχώς! Το vault σας είναι διαθέσιμο.
|
||||
@@ -149,6 +149,8 @@ preferences.general.theme.automatic=Αυτόματα
|
||||
preferences.general.theme.light=Ανοιχτό
|
||||
preferences.general.theme.dark=Σκούρο
|
||||
preferences.general.unlockThemes=Ξεκλείδωσε το σκούρο θέμα
|
||||
preferences.general.showMinimizeButton=Εμφάνιση κουμπιού ελαχιστοποίησης
|
||||
preferences.general.showTrayIcon=Εμφάνιση εικονιδίου κοντά στο ρολόι (απαιτεί επανεκκίνηση)
|
||||
preferences.general.startHidden=Απόκρυψη παραθύρου όταν ξεκινά το Cryptomator
|
||||
preferences.general.debugLogging=Ενεργοποίηση καταγραφής σφαλμάτων
|
||||
preferences.general.debugDirectory=Αποκάλυψη αρχείων καταγραφής
|
||||
@@ -200,7 +202,7 @@ stats.read.accessCount=Συνολικές αναγνώσεις: %d
|
||||
stats.write.throughput.idle=Εγγραφή: ηρεμία
|
||||
stats.write.throughput.kibs=Εγγραφή: %.2f kiB/s
|
||||
stats.write.throughput.mibs=Εγγραφή: %.2f MiB/s
|
||||
stats.write.total.data.none=Ανάγνωση δεδομένων: -
|
||||
stats.write.total.data.none=Δεδομένα που γράφηκαν: -
|
||||
stats.write.total.data.kib=Δεδομένα που γράφτηκαν: %.1f kiB
|
||||
stats.write.total.data.mib=Δεδομένα που γράφτηκαν: %.1f MiB
|
||||
stats.write.total.data.gib=Δεδομένα που γράφτηκαν: %.1f GiB
|
||||
|
||||
@@ -95,7 +95,7 @@ forgetPassword.confirmBtn=Olvidar contraseña
|
||||
# Unlock
|
||||
unlock.title=Desbloquear bóveda
|
||||
unlock.passwordPrompt=Ingresar contraseña para "%s":
|
||||
unlock.savePassword=Guardar contraseña
|
||||
unlock.savePassword=Recordar contraseña
|
||||
unlock.unlockBtn=Desbloquear
|
||||
## Success
|
||||
unlock.success.message=¡"%s" se desbloqueó con éxito! La bóveda ya es accesible.
|
||||
@@ -109,6 +109,7 @@ unlock.error.invalidMountPoint.existing=El punto de montaje/carpeta ya existe o
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
lock.forced.heading=Bloqueo automático fallido
|
||||
lock.forced.message=El bloqueo de "%s" fue bloqueado por operaciones pendientes o archivos abiertos. Puede forzar el bloqueo de esta bóveda, sin embargo, interrumpir la I/O puede provocar la pérdida de datos no guardados.
|
||||
lock.forced.confirmBtn=Forzar bloqueo
|
||||
## Failure
|
||||
@@ -148,6 +149,8 @@ preferences.general.theme.automatic=Automático
|
||||
preferences.general.theme.light=Claro
|
||||
preferences.general.theme.dark=Oscuro
|
||||
preferences.general.unlockThemes=Desbloquear el modo oscuro
|
||||
preferences.general.showMinimizeButton=Mostrar botón minimizar
|
||||
preferences.general.showTrayIcon=Mostrar icono de bandeja (requiere reiniciar)
|
||||
preferences.general.startHidden=Ocultar ventana al iniciar Cryptomator
|
||||
preferences.general.debugLogging=Habilitar registro de depuración
|
||||
preferences.general.debugDirectory=Revelar archivos de registro
|
||||
@@ -199,7 +202,7 @@ stats.read.accessCount=Total leídos: %d
|
||||
stats.write.throughput.idle=Escritura: inactivo
|
||||
stats.write.throughput.kibs=Escritura: %.2f kiB/s
|
||||
stats.write.throughput.mibs=Escritura: %.2f MiB/s
|
||||
stats.write.total.data.none=Datos leídos: -
|
||||
stats.write.total.data.none=Datos escritos:-
|
||||
stats.write.total.data.kib=Datos escritos: %.1f kiB
|
||||
stats.write.total.data.mib=Datos escritos: %.1f MiB
|
||||
stats.write.total.data.gib=Datos escritos: %.1f GiB
|
||||
|
||||
@@ -95,7 +95,7 @@ forgetPassword.confirmBtn=Oublier le mot de passe
|
||||
# Unlock
|
||||
unlock.title=Déverrouiller le coffre
|
||||
unlock.passwordPrompt=Entrez le mot de passe pour “%s” :
|
||||
unlock.savePassword=Enregistrer le mot de passe
|
||||
unlock.savePassword=Mémoriser le mot de passe
|
||||
unlock.unlockBtn=Déverrouiller
|
||||
## Success
|
||||
unlock.success.message=“%s” déverrouillé ! Le contenu de votre coffre est maintenant accessible.
|
||||
@@ -113,7 +113,7 @@ lock.forced.heading=Le verrouillage normal a échoué
|
||||
lock.forced.message=Le verrouillage de «%s» a été bloqué par des opérations en attente ou des fichiers ouverts. Vous pouvez forcer le verrouillage de ce coffre, mais l'interruption d'E/S peut entraîner la perte de données non enregistrées.
|
||||
lock.forced.confirmBtn=Forcer le verrouillage
|
||||
## Failure
|
||||
lock.fail.heading=Le verrouillage du coffre-fort a échoué.
|
||||
lock.fail.heading=Le verrouillage du coffre a échoué.
|
||||
lock.fail.message=Le coffre-fort "%s" n'a pas pu être verrouillé. Assurez-vous que le travail non sauvegardé est sauvegardé ailleurs et que les opérations importantes de lecture/écriture sont bien terminées. Pour fermer le coffre-fort, tuez le processus Cryptomator.
|
||||
|
||||
# Migration
|
||||
@@ -149,6 +149,8 @@ preferences.general.theme.automatic=Automatique
|
||||
preferences.general.theme.light=Clair
|
||||
preferences.general.theme.dark=Sombre
|
||||
preferences.general.unlockThemes=Débloquer le mode nuit
|
||||
preferences.general.showMinimizeButton=Afficher le bouton de réduction
|
||||
preferences.general.showTrayIcon=Afficher l'icône de la barre des tâches (redémarrage requis)
|
||||
preferences.general.startHidden=Démarrer Cryptomator en mode caché
|
||||
preferences.general.debugLogging=Activer les logs debug
|
||||
preferences.general.debugDirectory=Afficher le journal
|
||||
@@ -200,7 +202,7 @@ stats.read.accessCount=Total des lectures: %d
|
||||
stats.write.throughput.idle=Écriture : inactif
|
||||
stats.write.throughput.kibs=Écriture : %.2f kiO/s
|
||||
stats.write.throughput.mibs=Écriture : %.2f Mo/s
|
||||
stats.write.total.data.none=Lecture des données : -
|
||||
stats.write.total.data.none=Données écrites : -
|
||||
stats.write.total.data.kib=Données écrites : %.1f kiO
|
||||
stats.write.total.data.mib=Données écrites : %.1f MiO
|
||||
stats.write.total.data.gib=Données écrites : %.1f GiO
|
||||
|
||||
@@ -17,9 +17,11 @@ generic.error.title=कोई अनपेक्षित त्रुटि ह
|
||||
generic.error.instruction=ऐसा नहीं होना चाहिए था। कृपया नीचे त्रुटि पाठ की रिपोर्ट करें और इस त्रुटि के लिए क्या कदम उठाए, इसका विवरण शामिल करें।
|
||||
|
||||
# Defaults
|
||||
defaults.vault.vaultName=गुप्त तिजोरी
|
||||
|
||||
# Tray Menu
|
||||
traymenu.showMainWindow=दिखाएँ
|
||||
traymenu.showPreferencesWindow=प्राथमिकताएं
|
||||
traymenu.lockAllVaults=सभी को लॉक करें
|
||||
traymenu.quitApplication=बाहर निकलें
|
||||
traymenu.vault.unlock=अनलॉक करें
|
||||
@@ -42,9 +44,21 @@ addvaultwizard.new.locationPrompt=…
|
||||
addvaultwizard.new.directoryPickerLabel=अपने पसंद की जगह डालें
|
||||
addvaultwizard.new.directoryPickerButton=चुनें…
|
||||
addvaultwizard.new.directoryPickerTitle=निर्देशिका चुनें
|
||||
addvaultwizard.new.fileAlreadyExists=तिजोरी इस रास्ते पर नहीं बनाई जा सकती क्योंकि कुछ वस्तु पहले से मौजूद है।
|
||||
addvaultwizard.new.locationDoesNotExist=तिजोरी इस रास्ते पर नहीं बनाई जा सकती क्योंकि कम से कम एक पथ घटक मौजूद नहीं है।
|
||||
addvaultwizard.new.invalidName=अमान्य वॉल्ट नाम। कृपया एक नियमित निर्देशिका नाम पर विचार करें।
|
||||
### Password
|
||||
addvaultwizard.new.createVaultBtn=वॉल्ट बनाएं
|
||||
addvaultwizard.new.generateRecoveryKeyChoice=आप अपने पासवर्ड के बिना अपने डेटा तक नहीं पहुंच पाएंगे। क्या आप उस वक़्त के लिए एक पुनर्प्राप्ति कुंजी चाहते हैं जब आप अपना पासवर्ड खो देते हैं?
|
||||
addvaultwizard.new.generateRecoveryKeyChoice.yes=हाँ कृपया, पछतावा से बेहतर सुरक्षा
|
||||
addvaultwizard.new.generateRecoveryKeyChoice.no=नहीं धन्यवाद, मैं अपना पासवर्ड नहीं खोऊंगा
|
||||
### Information
|
||||
addvault.new.readme.storageLocation.fileName=IMPORTANT.rtf
|
||||
addvault.new.readme.storageLocation.1=⚠️ तिजोरी की फ़ाइलें ⚠️
|
||||
addvault.new.readme.storageLocation.2=यह आपकी तिजोरी का भंडारण स्थान है।
|
||||
addvault.new.readme.storageLocation.3=ऐसा न करें
|
||||
addvault.new.readme.storageLocation.4=• इस निर्देशिका के भीतर किसी भी फाइल को बदल दें या
|
||||
addvault.new.readme.storageLocation.5=• • इस डायरेक्टरी में एन्क्रिप्शन के लिए कोई भी फाइल पेस्ट करें।
|
||||
## Existing
|
||||
addvaultwizard.existing.chooseBtn=चुनें…
|
||||
## Success
|
||||
@@ -75,6 +89,7 @@ migration.title=वाउल्ट को अपग्रेड करें
|
||||
## Impossible
|
||||
|
||||
# Preferences
|
||||
preferences.title=प्राथमिकताएं
|
||||
## General
|
||||
preferences.general=सामान्य
|
||||
## Volume
|
||||
@@ -88,6 +103,7 @@ preferences.general=सामान्य
|
||||
|
||||
# Main Window
|
||||
main.closeBtn.tooltip=बंद करें
|
||||
main.preferencesBtn.tooltip=प्राथमिकताएं
|
||||
## Drag 'n' Drop
|
||||
## Vault List
|
||||
main.vaultlist.addVaultBtn=वाउल्ट डालें
|
||||
|
||||
@@ -0,0 +1,300 @@
|
||||
# Locale Specific CSS files such as CJK, RTL,...
|
||||
|
||||
# Generics
|
||||
## Button
|
||||
generic.button.apply=Alkalmaz
|
||||
generic.button.back=Vissza
|
||||
generic.button.cancel=Mégse
|
||||
generic.button.change=Változtat
|
||||
generic.button.close=Bezár
|
||||
generic.button.copy=Másolás
|
||||
generic.button.copied=Másolva!
|
||||
generic.button.done=Kész
|
||||
generic.button.next=Következő
|
||||
generic.button.print=Nyomtatás
|
||||
## Error
|
||||
generic.error.title=Egy váratlan hiba történt
|
||||
generic.error.instruction=Ennek nem lett volna szabad megtörténnie. Kérjük jelezze a hibát az alábbi szöveggel valamint a hiba reprodukálásához szükséges lépésekkel.
|
||||
|
||||
# Defaults
|
||||
defaults.vault.vaultName=Széf
|
||||
|
||||
# Tray Menu
|
||||
traymenu.showMainWindow=Megmutatás
|
||||
traymenu.showPreferencesWindow=Beállítások
|
||||
traymenu.lockAllVaults=Az összes zárolása
|
||||
traymenu.quitApplication=Kilépés
|
||||
traymenu.vault.unlock=Feloldás
|
||||
traymenu.vault.lock=Zárolás
|
||||
traymenu.vault.reveal=Megmutatás
|
||||
|
||||
# Add Vault Wizard
|
||||
addvaultwizard.title=Széf hozzáadása
|
||||
## Welcome
|
||||
addvaultwizard.welcome.newButton=Új széf létrehozása
|
||||
addvaultwizard.welcome.existingButton=Meglévő széf megnyitása
|
||||
## New
|
||||
### Name
|
||||
addvaultwizard.new.nameInstruction=Válasszon egy nevet az új széf számára
|
||||
addvaultwizard.new.namePrompt=A széf neve
|
||||
### Location
|
||||
addvaultwizard.new.locationInstruction=Hova mentse a Cryptomator a széf titkosított fájljait?
|
||||
addvaultwizard.new.locationLabel=Tárolási hely
|
||||
addvaultwizard.new.directoryPickerLabel=Egyedi hely
|
||||
addvaultwizard.new.directoryPickerButton=Választás…
|
||||
addvaultwizard.new.directoryPickerTitle=Könyvtár kiválasztása
|
||||
addvaultwizard.new.fileAlreadyExists=Nem lehet a széfet létrehozni ezen a helyen, mert egy fájl már létezik itt.
|
||||
addvaultwizard.new.locationDoesNotExist=Nem lehet a széfet létrehozni ezen a helyen, mert az útvonal legalább egy darabja nem létezik.
|
||||
addvaultwizard.new.invalidName=Érvénytelen széf elnevezés. Kérjük vegye figyelembe a szabályos könyvtárelnevezésre vonatkozó szabályokat.
|
||||
### Password
|
||||
addvaultwizard.new.createVaultBtn=Új széf létrehozása
|
||||
addvaultwizard.new.generateRecoveryKeyChoice=Nem fog tudni hozzáférni az adataihoz a jelszó nélkül. Akar egy visszaállítási kulcsot arra az esetre, ha elveszíti a jelszavát?
|
||||
addvaultwizard.new.generateRecoveryKeyChoice.yes=Igen kérem, jobb félni, mint megijedni.
|
||||
addvaultwizard.new.generateRecoveryKeyChoice.no=Nem köszönöm, nem fogom elveszíteni a jelszavam.
|
||||
### Information
|
||||
addvault.new.readme.storageLocation.fileName=FONTOS.rtf
|
||||
addvault.new.readme.storageLocation.1=⚠️ SZÉF FÁJLOK ⚠️
|
||||
addvault.new.readme.storageLocation.2=Ez a széfjének a tárolási helye.
|
||||
addvault.new.readme.storageLocation.3=NE
|
||||
addvault.new.readme.storageLocation.4=• ne módosítson semmilyen fájlt ebbe a könyvtárba
|
||||
addvault.new.readme.storageLocation.5=• ne tegyen titkosítani való fájlokat ebbe a könyvtárba
|
||||
addvault.new.readme.storageLocation.6=Ha fájlokat akr titkosítani és a széf tartalmát akarja szerkeszteni akkor tegye a következőt:
|
||||
addvault.new.readme.storageLocation.7=1. Adja hozzá a széfet a Cryptomator-hoz.
|
||||
addvault.new.readme.storageLocation.8=2. Nyissa meg a széfet a Cryptomator-ban.
|
||||
addvault.new.readme.storageLocation.9=3. Nyissa meg a hozzáférési helyet a "Megjelenítés" gombra való kattintással.
|
||||
addvault.new.readme.storageLocation.10=Ha segítségre van szüksége, akkor látogasson el a dokumentáció oldalára: %s
|
||||
addvault.new.readme.accessLocation.fileName=ÜDVÖZÖLJÜK.rtf
|
||||
addvault.new.readme.accessLocation.1=🔐️ TITKOSÍTOTT KÖTET 🔐️
|
||||
addvault.new.readme.accessLocation.2=Ez a széf hozzáférési helye.
|
||||
addvault.new.readme.accessLocation.3=Bármilyen, a kötethez hozzáadott fájl titkosításra kerül a Cryptomator által. Úgy dolgozhat vele, mint minden más meghajtóval/mappával. Ez az egyetlen dekódolt tartalmi nézet. A fájlai folyamatosan titkosítva maradnak a merevlemezén.
|
||||
addvault.new.readme.accessLocation.4=Bátran eltávolíthatja ezt a fájlt.
|
||||
## Existing
|
||||
addvaultwizard.existing.instruction=Válassza ki a már létező széfjéhez tartozó "masterkey.cryptomator" fájlt.
|
||||
addvaultwizard.existing.chooseBtn=Kiválaszt…
|
||||
addvaultwizard.existing.filePickerTitle=Mesterkulcs fájl kiválasztása
|
||||
## Success
|
||||
addvaultwizard.success.nextStepsInstructions=Széf létrehozva "%s".\nA tartalom eléréséhez, vagy hozzáadásához fel kell oldania a széfet. Alternatív megoldásként később bármikor feloldhatja.
|
||||
addvaultwizard.success.unlockNow=Azonnali feloldás
|
||||
|
||||
# Remove Vault
|
||||
removeVault.title=Széf eltávolitása
|
||||
removeVault.information=Ez kizárolag a Cryptomator-ból távolitja el ezt a széfet. Később hozzáadhatja újra. A titkosított fájlokat nem törli a merevlemezről.
|
||||
removeVault.confirmBtn=Széf eltávolitása
|
||||
|
||||
# Change Password
|
||||
changepassword.title=Jelszó megváltoztatása
|
||||
changepassword.enterOldPassword=Írja be a jelenlegi jelszavat a következő széfhez "%s"
|
||||
changepassword.finalConfirmation=Megértettem, hogy nem fogok hozzáférni az adataimhoz amennyiben elfelejtem a jelszavam
|
||||
|
||||
# Forget Password
|
||||
forgetPassword.title=Jelszó elfelejtése
|
||||
forgetPassword.information=Eltávolítja a széf mentett jelszavát a rendszere kulcstartójából.
|
||||
forgetPassword.confirmBtn=Jelszó elfelejtése
|
||||
|
||||
# Unlock
|
||||
unlock.title=Széf feloldása
|
||||
unlock.passwordPrompt=Írja be a jelszavát a következő széfhez "%s":
|
||||
unlock.unlockBtn=Feloldás
|
||||
## Success
|
||||
unlock.success.message="%s" sikreresen feloldásra került! Mostmár hozzáférhet a széféhez.
|
||||
unlock.success.rememberChoice=Jegyezze meg a választást és ne mutassa többet
|
||||
unlock.success.revealBtn=Széf megjelenítése
|
||||
## Failure
|
||||
unlock.error.heading=Nem lehet feloldani a széfet
|
||||
### Invalid Mount Point
|
||||
unlock.error.invalidMountPoint.notExisting=A csatolási pont "%s" nem egy könyvtár, nem üres vagy nem létezik.
|
||||
unlock.error.invalidMountPoint.existing=A csatolási pont "%s" már létezik vagy a already exists or szülőmappa hiányzik.
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
## Failure
|
||||
|
||||
# Migration
|
||||
migration.title=Széf frissítése
|
||||
## Start
|
||||
migration.start.prompt=A "%s" széf formátuma frissítésre szorul. A folytatás előtt győződjön meg arról, hogy nincs függőben lévő szinkronizálás, amely befolyásolja ezt a széfet.
|
||||
migration.start.confirm=Igen, a széfem teljes mértékben szinkronizálva van
|
||||
## Run
|
||||
migration.run.enterPassword=Írja be a jelszót a következőhöz Enter the password for "%s"
|
||||
migration.run.startMigrationBtn=Széf frissítése
|
||||
migration.run.progressHint=Ez eltarthat egy darabig…
|
||||
## Sucess
|
||||
migration.success.nextStepsInstructions=A "%s" sikeresen migrálva. \nMost már feloldhatja a széfet.
|
||||
migration.success.unlockNow=Azonnali feloldás
|
||||
## Missing file system capabilities
|
||||
migration.error.missingFileSystemCapabilities.title=Nem támogatott fájlrendszer
|
||||
migration.error.missingFileSystemCapabilities.description=A migráció nem kezdődött el, mert a széf nem megfelelő fájlrendszeren található.
|
||||
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=A fájlrendszer nem támogatja a hosszú fájlneveket.
|
||||
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=A fájlrendszer nem támogatja a hosszú útvonalakat.
|
||||
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=A fájlrendszer nem teszi lehetővé az olvasást.
|
||||
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=A fájlrendszer nem teszi lehetővé az írást.
|
||||
## Impossible
|
||||
migration.impossible.heading=A széf frissítése sikertelen
|
||||
migration.impossible.reason=A széfet nem lehet automatikusan frissíteni, mert a tárolási helye vagy a hozzáférési pontja nem kompatibilis.
|
||||
migration.impossible.moreInfo=A széf továbbra is megnyitható marad egy régebbi verzióval. A széf kézi frissítésével kapcsolatos utasításokért keresse fel a következő címet:
|
||||
|
||||
# Preferences
|
||||
preferences.title=Beállítások
|
||||
## General
|
||||
preferences.general=Általános
|
||||
preferences.general.theme=Megjelenés
|
||||
preferences.general.theme.automatic=Autómatikus
|
||||
preferences.general.theme.light=Világos
|
||||
preferences.general.theme.dark=Sötét
|
||||
preferences.general.unlockThemes=Sötét mód feloldása
|
||||
preferences.general.startHidden=Az ablak elrejtése a Cryptomator indítása után
|
||||
preferences.general.debugLogging=Hibakeresési naplózás engedélyezése
|
||||
preferences.general.debugDirectory=Naplófájlok megjelenítése
|
||||
preferences.general.autoStart=Cryptomator indítása a rendszerrel együtt
|
||||
preferences.general.keychainBackend=Itt tárolja a jelszavakat
|
||||
preferences.general.interfaceOrientation=Felhasználói felület orientációja
|
||||
preferences.general.interfaceOrientation.ltr=Balról jobbra
|
||||
preferences.general.interfaceOrientation.rtl=Jobbról balra
|
||||
## Volume
|
||||
preferences.volume=Virtuális meghajtó
|
||||
preferences.volume.type=Kötet tipusa
|
||||
## Updates
|
||||
preferences.updates=Frissítések
|
||||
preferences.updates.currentVersion=Jelenlegi verzió: %s
|
||||
preferences.updates.autoUpdateCheck=Frissítések autómatikus keresése
|
||||
preferences.updates.checkNowBtn=Ellenőrzés most
|
||||
preferences.updates.updateAvailable=Frissítés a %s verzióra elérhető.
|
||||
## Donation Key
|
||||
preferences.donationKey=Adomány
|
||||
preferences.donationKey.registeredFor=Regisztrálva %s számára
|
||||
preferences.donationKey.noDonationKey=Nem található érvényes adománykulcs. Mint egy licenckulcs, csak olyan nagyszerű emberek számára, akik ingyenes szofvereket használnak. ;-)
|
||||
preferences.donationKey.getDonationKey=Adománykulcs beszerzése
|
||||
## About
|
||||
preferences.about=Rólunk
|
||||
|
||||
# Vault Statistics
|
||||
stats.title=Statisztika ehhez %s
|
||||
stats.cacheHitRate=Gyorsítótár találati arány
|
||||
## Read
|
||||
stats.read.throughput.idle=Olvasás: tétlen
|
||||
stats.read.throughput.kibs=Olvasás: %.2f kiB/s
|
||||
stats.read.throughput.mibs=Olvasás: %.2f MiB/s
|
||||
stats.read.total.data.none=Olvasott adat: -
|
||||
stats.read.total.data.kib=Olvasott adat: %.1f kiB
|
||||
stats.read.total.data.mib=Olvasott adat: %.1f MiB
|
||||
stats.read.total.data.gib=Olvasott adat: %.1f GiB
|
||||
stats.decr.total.data.none=Dekódolt adat: -
|
||||
stats.decr.total.data.kib=Dekódolt adat: %.1f kiB
|
||||
stats.decr.total.data.mib=Dekódolt adat: %.1f MiB
|
||||
stats.decr.total.data.gib=Dekódolt adat: %.1f GiB
|
||||
stats.read.accessCount=Összes olvasás: %d
|
||||
## Write
|
||||
stats.write.throughput.idle=Írás: tétlen
|
||||
stats.write.throughput.kibs=Írás: %.2f kiB/s
|
||||
stats.write.throughput.mibs=Írás: %.2f MiB/s
|
||||
stats.write.total.data.kib=Írott adat: %.1f kiB
|
||||
stats.write.total.data.mib=Írott adat: %.1f MiB
|
||||
stats.write.total.data.gib=Írott adat: %.1f GiB
|
||||
stats.encr.total.data.none=Titkosított adat: -
|
||||
stats.encr.total.data.kib=Titkosított adat: %.1f kiB
|
||||
stats.encr.total.data.mib=Titkosított adat: %.1f MiB
|
||||
stats.encr.total.data.gib=Titkosított adat: %.1f GiB
|
||||
stats.write.accessCount=Összes írás: %d
|
||||
|
||||
# Main Window
|
||||
main.closeBtn.tooltip=Bezárás
|
||||
main.minimizeBtn.tooltip=Minimalizálás
|
||||
main.preferencesBtn.tooltip=Beállítások
|
||||
main.debugModeEnabled.tooltip=A hibakeresési mód aktiválva van
|
||||
main.donationKeyMissing.tooltip=Kérjük, fontolja meg az adományozást
|
||||
## Drag 'n' Drop
|
||||
main.dropZone.dropVault=Adja hozzá ezt a széfet
|
||||
main.dropZone.unknownDragboardContent=Ha egy széfet szeretne hozzáadni, akkor húzza át erre az ablakra.
|
||||
## Vault List
|
||||
main.vaultlist.emptyList.onboardingInstruction=Kattintson ide egy széf hozzáadásához
|
||||
main.vaultlist.contextMenu.remove=Széf eltávolítása…
|
||||
main.vaultlist.addVaultBtn=Széf hozzáadása
|
||||
## Vault Detail
|
||||
### Welcome
|
||||
main.vaultDetail.welcomeOnboarding=Köszönjük, hogy a Cryptomator programot választotta a fájlai védelmére. Ha segítségre van szüksége, akkor olvassa el a kezdő útmutatónk lépéseit:
|
||||
### Locked
|
||||
main.vaultDetail.lockedStatus=ZÁROLVA
|
||||
main.vaultDetail.unlockBtn=Feloldás…
|
||||
main.vaultDetail.unlockNowBtn=Azonnali feloldás
|
||||
main.vaultDetail.optionsBtn=Széf beállítások
|
||||
main.vaultDetail.passwordSavedInKeychain=Jelszó mentve
|
||||
### Unlocked
|
||||
main.vaultDetail.unlockedStatus=FELOLDVA
|
||||
main.vaultDetail.accessLocation=A széf tartalma itt érhető el:
|
||||
main.vaultDetail.revealBtn=Széf megjelenítése
|
||||
main.vaultDetail.lockBtn=Zárolás
|
||||
main.vaultDetail.bytesPerSecondRead=Olvasás:
|
||||
main.vaultDetail.bytesPerSecondWritten=Írás:
|
||||
main.vaultDetail.throughput.idle=tétlen
|
||||
main.vaultDetail.stats=Széf statisztika
|
||||
### Missing
|
||||
main.vaultDetail.missing.info=A Cryptomator nem talált széfet ezen az útvonalon.
|
||||
main.vaultDetail.missing.recheck=Ellenőrizze újra
|
||||
main.vaultDetail.missing.remove=A széf eltávolítása a listából…
|
||||
main.vaultDetail.missing.changeLocation=A széf helyének megváltoztatása…
|
||||
### Needs Migration
|
||||
main.vaultDetail.migrateButton=Széf frissítése
|
||||
main.vaultDetail.migratePrompt=A széfet új formátumra kell frissíteni, mielőtt hozzáférhet
|
||||
|
||||
# Wrong File Alert
|
||||
wrongFileAlert.title=Hogyan lehet fájlokat titkosítani
|
||||
wrongFileAlert.header.title=Próbálta ezeket a fájlokat titkosítani?
|
||||
wrongFileAlert.header.lead=Erre a célra a Cryptomator egy kötetet biztosít a rendszer fájlkezelőjében.
|
||||
wrongFileAlert.instruction.0=Hogy titkosítsa a fájlokat kövesse a következő lépéseket:
|
||||
wrongFileAlert.instruction.1=1. Oldja fel a széfet.
|
||||
wrongFileAlert.instruction.2=2. Kattintson a "Megjelenítés" gombra, hogy megnyissa a kötetet a fájlkezelőjében.
|
||||
wrongFileAlert.instruction.3=3. Adjon hozzá fájlokat a kötethez.
|
||||
wrongFileAlert.link=További segítségért látogasson el ide
|
||||
|
||||
# Vault Options
|
||||
## General
|
||||
vaultOptions.general=Általános
|
||||
vaultOptions.general.vaultName=A széf neve
|
||||
vaultOptions.general.unlockAfterStartup=A széf feloldása a Cryptomator indításakor
|
||||
vaultOptions.general.actionAfterUnlock=Sikeres feloldás után
|
||||
vaultOptions.general.actionAfterUnlock.ignore=Ne tegyen semmit
|
||||
vaultOptions.general.actionAfterUnlock.reveal=Jelenítse meg a kötetet
|
||||
vaultOptions.general.actionAfterUnlock.ask=Kérdez
|
||||
## Mount
|
||||
vaultOptions.mount=Felcsatolás
|
||||
vaultOptions.mount.readonly=Csak-olvasható
|
||||
vaultOptions.mount.customMountFlags=Egyedi csatolási paraméterek
|
||||
vaultOptions.mount.winDriveLetterOccupied=foglalt
|
||||
vaultOptions.mount.mountPoint=Csatolási pont
|
||||
vaultOptions.mount.mountPoint.auto=Válasszon egy megfelelő helyet automatikusan
|
||||
vaultOptions.mount.mountPoint.driveLetter=Használja a kiválasztott meghajtó betűjelét
|
||||
vaultOptions.mount.mountPoint.custom=Egyedi útvonal
|
||||
vaultOptions.mount.mountPoint.directoryPickerButton=Kiválaszt…
|
||||
vaultOptions.mount.mountPoint.directoryPickerTitle=Válasszon egy üres könyvtárat
|
||||
## Master Key
|
||||
vaultOptions.masterkey=Jelszó
|
||||
vaultOptions.masterkey.changePasswordBtn=Jelszó megváltoztatása
|
||||
vaultOptions.masterkey.forgetSavedPasswordBtn=Mentett jelszó törlése
|
||||
vaultOptions.masterkey.recoveryKeyExpanation=A helyreállítási kulcs az egyetlen módja annak, hogy visszaállítsa a széfhez való hozzáférést, ha elveíti a jelszavát.
|
||||
vaultOptions.masterkey.showRecoveryKeyBtn=Visszaállítási kulcs megjelenítése
|
||||
vaultOptions.masterkey.recoverPasswordBtn=Jelszó visszaállítása
|
||||
|
||||
# Recovery Key
|
||||
recoveryKey.title=Visszaállítási kulcs
|
||||
recoveryKey.enterPassword.prompt=Írja be a jelszavát a "%s" visszaállítási kulcsának megjelenítéséhez:
|
||||
recoveryKey.display.message=A következő helyreállítási kulcs használható a "%s" hozzáférésének visszaállítására:
|
||||
recoveryKey.display.StorageHints=Tartsa nagyon biztonságos helyen. pl.:\n •Tárolja egy jelszókezelővel\n •Mentse el egy USB meghajtóra\n •Nyomtassa egy papírra
|
||||
recoveryKey.recover.prompt=Írja be a visszaállítási kulcsát a következőhöz "%s":
|
||||
recoveryKey.recover.validKey=Ez egy érvényes visszaállítási kulcs
|
||||
recoveryKey.printout.heading=Cryptomator visszaállítási kulcs\n"%s"\n
|
||||
|
||||
# New Password
|
||||
newPassword.promptText=Adjon meg egy új jelszót
|
||||
newPassword.reenterPassword=Az új jelszó megerősítése
|
||||
newPassword.passwordsMatch=A jelszavak megegyeznek!
|
||||
newPassword.passwordsDoNotMatch=A jelszavak nem egyeznek meg
|
||||
passwordStrength.messageLabel.tooShort=Használjon legalább %d karaktert
|
||||
passwordStrength.messageLabel.0=Nagyon gyenge
|
||||
passwordStrength.messageLabel.1=Gyenge
|
||||
passwordStrength.messageLabel.2=Átlagos
|
||||
passwordStrength.messageLabel.3=Erős
|
||||
passwordStrength.messageLabel.4=Nagyon erős
|
||||
|
||||
# Quit
|
||||
quit.prompt=Kilép az alkalmazásból? Vannak még lezáratlan széfek.
|
||||
quit.lockAndQuit=Zárolás és kilépés
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user