diff --git a/.crowdin.yml b/.crowdin.yml new file mode 100644 index 00000000..d0ae7b74 --- /dev/null +++ b/.crowdin.yml @@ -0,0 +1,5 @@ +escape_special_characters: 0 +commit_message: '[ci skip]' +files: + - source: /presentation/src/main/res/values/strings.xml + translation: /presentation/src/main/res/values-%two_letters_code%/strings.xml diff --git a/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md similarity index 100% rename from CODE_OF_CONDUCT.md rename to .github/CODE_OF_CONDUCT.md diff --git a/CONTRIBUTING.md b/.github/CONTRIBUTING.md similarity index 72% rename from CONTRIBUTING.md rename to .github/CONTRIBUTING.md index 63e774b2..7baabb71 100644 --- a/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -4,12 +4,12 @@ - Ensure you're running the latest version of Cryptomator. - Ensure the bug is related to the Android version of Cryptomator. Bugs concerning the Cryptomator desktop application and iOS app can be reported on the [Cryptomator issues list](https://github.com/cryptomator/cryptomator/issues) and [Cryptomator for iOS issues list](https://github.com/cryptomator/cryptomator-ios/issues) respectively. -- Ensure the bug was not [already reported](https://github.com/cryptomator/cryptomator-android/issues). You can also check out our [FAQ](https://community.cryptomator.org/c/faq). -- If you're unable to find an open issue addressing the problem, [submit a new one](https://github.com/cryptomator/cryptomator-android/issues/new). +- Ensure the bug was not [already reported](https://github.com/cryptomator/android/issues). You can also check out our [FAQ](https://community.cryptomator.org/c/faq). +- If you're unable to find an open issue addressing the problem, [submit a new one](https://github.com/cryptomator/android/issues/new). ## Code of Conduct -Help us keep Cryptomator open and inclusive. Please read and follow our [Code of Conduct](https://github.com/cryptomator/cryptomator-android/blob/master/CODE_OF_CONDUCT.md). +Help us keep Cryptomator open and inclusive. Please read and follow our [Code of Conduct](https://github.com/cryptomator/android/blob/develop/.github/CODE_OF_CONDUCT.md). ## Above all, thank you for your contributions diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index f4f8e9d8..53d94eee 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -5,18 +5,12 @@ labels: type:bug --- - ### Description diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..94f5f512 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Help & Support + url: https://community.cryptomator.org/ + about: You will find answers in our community forum + - name: User Manual + url: https://docs.cryptomator.org/ + about: Read the Cryptomator documentation here diff --git a/.github/ISSUE_TEMPLATE/feature.md b/.github/ISSUE_TEMPLATE/feature.md index 42a54e93..91b7c00b 100644 --- a/.github/ISSUE_TEMPLATE/feature.md +++ b/.github/ISSUE_TEMPLATE/feature.md @@ -5,16 +5,12 @@ labels: type:feature-request --- + ### Summary [One paragraph explanation of the feature.] @@ -29,4 +25,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.] \ No newline at end of file +[Add any other context or screenshots about the feature request here.] diff --git a/.github/SECURITY.md b/.github/SECURITY.md new file mode 100644 index 00000000..1bcb1adc --- /dev/null +++ b/.github/SECURITY.md @@ -0,0 +1,124 @@ +# Security Policy + +## Reporting a Vulnerability + +For reporting security-related vulnerabilities or exploits that [haven't been reported yet](https://github.com/cryptomator/android/labels/type%3Asecurity-issue), contact us at: security@cryptomator.org + +
+PGP Key + +``` +-----BEGIN PGP PUBLIC KEY BLOCK----- +Comment: GPGTools - https://gpgtools.org + +mQINBFbgeicBEADM9AcU6DTgM5KZnBaJc6x9DBLr+TCMHntTt7YM9GLTlO2Z43Jt +oYoyqdRWAY28veqpLEFgRvvVD3fdBj/KUOxF1cr2JsErwXqbjwaLq0o/0KIXz7UK +a6pQSemZKfpOtJrfacofOTwvG6AuG9uakBYNMyxuojyOkoh3xsYS1KZ7TwPgCdET +t8/zva41Pa5kh5+GeSZJdCuygG6ynPBJEpmK5V7Qizvics5fziXecF+QaFZijafv +YahfxokvF9pXCQTmV4m57NQma9uK0w83U9nJCPjEd+x3wK0Hxrc1ojy8ZFTA1YND +AQg/MTABgHbQQkXDQhjS/TloOObqtbMBqNSbcSXpaR4teaCWKBl1MSq00nJLj8db +vPJGqfg7UbXhlALggp029/kskYlR5SmbxWquLbl0Xre3fDHuHEiWcJL6MS3454Wt +Mno13/4UhOlRFh5g0pLmPz7seOTJjDqc9abn/RXOLq0+3qX0gC0bDm5aCE5dQ2MV +FMbrrlw/dZESNLZvtB3gOsramSry1R3HVZ0QJ2vMaF2cxewebqcYbuecUNj6bxpv +5LEhEmqz6dG1meLLWDsvQLPEUWEIJnfpBiDSm342yxJq4pXnVF+aqAQsCL3FpmvZ +2j0FgFOs7iXOcFUJIiR0xUmWPk1NWYcUowqmRW8pMM9nFUzFF99iggPznwARAQAB +tC1DcnlwdG9tYXRvciBTdXBwb3J0IDxzdXBwb3J0QGNyeXB0b21hdG9yLm9yZz6J +AkAEEwEKACoCGwMFCQcrKAAFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AFAleu2cQC +GQEACgkQI7Xb75TU2B3+7A/7BKRWdo5/moCCEbBzYQ7vRMLFdwmjFFlSZ7aGC0fP +YHdeUwxPbO0cATwmNpGMma7rBn1FDg3Vto6/wottGxm+XIRwlyY84CD1VZAihZ/e +WvjOO28/7VgRy6PGKzlhpDSoT8GwFOgO69e7bEff1Zj562RZe7nXc4tDivILMB++ +KgmmSgtddygmNQCS3RD3KssGo+l+cSjsg09F5WAJ6nQe8Jq2hICq+o/P6UXPI5lX +bhvWYDn4/8sRHsIlGpQYYDDe0fz7IQKuSLAHpF5upNDxj6dYb05F8PPVrk6MW6nL +/kf1fZ27DlLN5/NFvhhBRuwxxoAFqPS7Iel3z7L0JkRUYmGLVB5m9Cqiw6FK8JRv +OtvakdDoKb5lVAoN5NeBfNBSqEcXVF/EdfTfIyyo7hZRA6xFMEVbmYbzt0sj0djV +ZOey2TOFrTCpkHfUUDgKvk5sn+F3u8mmPIbqquEzlFJSFjcyiYYDv22rg1In+zKV +Xmw4BFZRDS6IVSQRGlskRGJBixCaGyDYxHXXT2cg4Rk9uiCX11+0E9qlAsg6xPe6 +rnaYDT8dU0AFyVpDpshflXH3kVQSpiqZS3jkAk1/54ODO8pE80Zrnd5m5AMuNcmX ++9MkZKE+h0882UskDs1dyt26GU2hoy4lAeRUaut7zIK/WO6nnuLaTvGWT95RDz+q +kD2JAiIEEwEKAAwFAleu2iYFgweGH4AACgkQZnuGbqgkCgnmCA//U22uhyEC/Tp3 +Cbt5lctQmqbgMbjRBaHQyW52tPFMaq8vXMbo/5TTtVC6xsp2PJT84cxAd8KX8hWq +cPtF4wWCJGng/AzyxQ5dWfGvA/ll32ygjtJN3P/AvA9KlhG+6XYmS8cPkBkJBi6B +2yCdZT1cXc/TPAFzjgAwz7K9g3awG0OeOc/CXymH0DD/snkiwKQoucStolYywZGc +GszjMQgeT4zOc1wtEz24uL3dMNDlDcQMAh56YvK2oB0iMYmAFyX/IS+f2bM9paXi +HX+mg/z53iwgf5ZXbslNDbMTJ5GNksjEGjCFfDHAdNdgT+lcW4l2U7q4PYUaN4LA +DE9j2OlOlQ9qjucOgoCStirnTP7XHd4p31lgdz8+THOQowB5Ji95OkiNQAFCfxBt +mcA/bWnJZQDm7L8RVzHovBpAaK6vUjxEvR+DXdESSzyZwkpsZwGZcyqGRT26R1/L +JE5WvjKufNc5v3Cat320MjyrLZwVGRgvEpDMoCw3nTWl9AtOj5vgaakEWr7AnqET +xk7UFbYmdTlQqkWuLKubz9Rx/FbrBmvd6vwTHy1Dfl6QyMWNCClatgN00Hxped/6 +CErg+R/RXd8apGxnOuWDqoujPn5LOHzgJolp1Ox16nTiZe2G+LbDr3hqRFi1wW6w +ioMB4KpkdA03uyxJSWmDEMiR1l3Oxom0KUNyeXB0b21hdG9yIFByZXNzIDxwcmVz +c0BjcnlwdG9tYXRvci5vcmc+iQI9BBMBCgAnBQJXrtnDAhsDBQkHKygABQsJCAcD +BRUKCQgLBRYCAwEAAh4BAheAAAoJECO12++U1NgdQYMQAKCIzNJF8rURQcFLSv3J +sPBjRy2HCzCWm21MuhU+bsaZx7U9M9dgEjzLfxN9s19VsBH3WKLgok2FgiYSGka3 +6Oy/P8VFLFmHs7dS9i2fro2eF7i4zj/ZD/9t0jM4ZIgLpbzr5sTBld292nsfXGob +xOJeOx3oWYyR2FO9VQxXjC3JvJyZkFgoy0tauS4Mvii4cF56wJGcxDTbe1s7UaRC +a/fh4zgISZSBE3rYhCawkN4mqMDM5RDjrdtjKUPWk345HcjjQ4Wos8xw4YbGbNr9 +Pc7m2URYJJ0jFM4tnoRF6cmA3bT9tm8pcOFg+K/ycVrltVEy+A8Wj8UGjyP1uI1t +EqWHN3LZpIGfW0w9AGrw7OUI9czXcukfngj/DsOU3WMBDIM8pW9+zBpr75yIS6lz +C0IqksLXSqX0b/Rby4O+wb6UZ1ZFkaim2GGtAZV+nGXtdnEXSNFiP7ykzjZ02m/1 +7CKyj3VmdAgT56zEIypFSfxm9gOWsJPmfhSyuE8bFyoitgNxpheZk6xZy4upVMPR +WK3hutScU0yDv2HVCiA3o3Ggy42nmz9HpGF6W2DmBx4bhMaVs6I2VFyKdQzmJD/3 +FCWjwz8PiEgVGHGPnD+WdPFLhrc/44gF4h/VuLjkubtULGuTVvgjeTIJ5LR1Gmwc +YOk6eD7MAJPzJVj5/PYFtIbKiQIiBBMBCgAMBQJXrtonBYMHhh+AAAoJEGZ7hm6o +JAoJBh4P/1w88YMTKUHpFTfJEwH2hK36BZN96Bf/k+vP7n1Xxp3NheInJblHFOt/ +ccsup6am+APrk8gGtlIVmtVc3nO8WMsWxfJxGDecyRsNbessnODv/llyg3tzVU/H +tLk7gLiK0TcIsOLfeNXGTxRRSKWjVFsNfuixNCzzHa7tFq6ddVn9VRZ8fqJB2p21 +OogWSDqUo9q9Wfb4RkYHguDx+8Jzoo/MxR1TSt8gUO2xDvEbqgeQiMCLF8R0lO3Y +zz0FrpyOsFU1CxVp+wo55bWv1UdwgQKQt4o0m5/zDJ2RAtscXpd4YcTE+XxKeK+4 +qhihhkhLGpKsxzK5m9/qwMbodHwoBCBzfalkUR9xOq9yQIeEoC8XYL62NqB3BCSU +KfWFIHxUkE9WH5zHWaV+bhrlNgk7nz3xBfPf1P2mNIc1VUHoNqOZOmWwz2VaKLSW +f3GIqx9wGythFbLdXmUoC3W//DDYgQnvImvkncMqQ5nRHPf8uHcLQK5WZyIxpgWT +eKon5G/cj0BTptcBhapMwSIyfaC5FV7so0/CkOA6R9Fyq2VpGoHy7XPhFS+6ieLi +KUWhCvbuf2deWbSaJ0peMdzy1p72UXwrsEM0M3Fz+Jd8zvCaFzf5Fx27+pAAdlfg +4bT3/2gSf7S+cU3+DnYOH0NeRt2Z2mjEKg9OwttTO/oDboQHdZlrtDRDcnlwdG9t +YXRvciBTZWN1cml0eS1UZWFtIDxzZWN1cml0eUBjcnlwdG9tYXRvci5vcmc+iQI9 +BBMBCgAnBQJXrtnWAhsDBQkHKygABQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJ +ECO12++U1NgddzoQAI78+Nvm6VvNuptXJjEmrpHRyKCnHF9wH5kxvF8WZCgpOkJ4 +vONmyS+9ZlepnT83MpGm/MzdIMCnDJmDmqmA5ISBRcD7k9Gjzz5rPKwE2zDyo0M0 +wF1L2UEUqAlcvE0e4twZcP2DGoNqdSf6IaWsXhQMb1a/rTMsoGZLuTB8kCbv6Ntl +ULahcRToTB2shsbZjzE896P6X5hDCfGWl0Jhcbf53pnXX1dOsEw3et9AGru1IUMs +UGM+wpgTwagRj+XB/WY1x9IznKtiHTq83Fvt+3bkg0+NIcV3GDqXDIUtqIwy8gDd +4KgBU+LkyxXFDa4OxLc53n6b+Iy1nDosM+SiqSzdCCgEs/dY1tQBn/7P1GT18dEe +tFgeH/c6wLvEpDIc9urAsYXf8H+1uy7glWpWTq8DE0yhCr4adjCqlIsVHQQO4UUW +NfqMGEFpJ+3HjSSwnvDGY78lLQh5d4vqWV435aNaMqZg0gJIA0FtiP1fRtmT73BG +N/tBNiBxretFR4B+x/TWqPd5iJV7/MAn/pa1WSOcaxzJrVUsjXdgLQCqcHWd4/w1 +f4DU9cJjl3sxZlMdAlg8Q1bF+pmjQQ4WKZkqMtwpoUilfVXmL42ay1LBCgW68/uJ +OTyGfp8ntUsbbm5raGsny3TLqnacyG9hxcPGNTzD1+MrbUvfsc7+4U0dCZTuiQIi +BBMBCgAMBQJXrtonBYMHhh+AAAoJEGZ7hm6oJAoJ1DQP/R+1drZiZQU45ChMbfTb +XQjJRsUOGZp3PTWtx4KrVFvE8ea0PF+DZX5gLJYIU+iZmPXRpzFu6dKPbcZ7RfRt +5RRH102zDZzijt2CQd7YLO8wxUFoWX9X7DGgxXEcNjl9kFVmnyHgiTwTzuZ0Zy4y +PvoiwrhcZmXEYbOeV40gLFie6wuzz5IIcs01e30xIs+1/1gwmgI5UnG3jveUgmcj +f/lvg3POKiwrY5Uzw1FSruJx21X06wTpDcfOACID4L7aY9eg2B/qL2Xj8nuhejqG ++1AVTMk2o6pxkvevHmxYQfEpuWGCw0RCBn9ObWwz6Zn5J9pjGbMrM+b1/M2Ouv3N +cpoGgCSahKNsRMKO7RMrBG0jtLcasPSgZFYPJSZAAb+YhxKUbpPHzDIwTEjgM7CL +gKSyRTKyp5IoFK53bpXL/ZIjkAhMvyDult6+BL6vI0+h3BBA9I0FF2Qhe139xLv/ +DS7aDiYAE9vGMGoeCBfxJPwUsDU3hrGe/wgL7fR6nmN7R2QffisBHKHsklORy9t3 +w3YFRd5sBAxv+EOcdkgXEmqKOfVQ8KU9adQcxPDGMAK/esjVwxUxsaf2PF5noxxW +3zL2ureUO/mMoH5Cwr0BuM3HFb82t1JJd4IXlLEyNvDMFMwD2d7h37bGK7Y5hEsl +zL7Dm+wQRY8sxg4QOZHbJjQXuQINBFbgeicBEADnkxGSEL1zwACaiVqADKC6/pgO +MMWjxoENBT6r8Vnp1D5hfNDkEi9iXUpCEO6nzywBf3/4c4Yk1wBOBZ7YWyWXMf4v +2g1evxELO5z1UlAwna6HSl7G0omIBqzz1Er5IS7C9WEZM8ZggwcuswCrbxfz4+fN +t7cCL5QyOvuxez+vrn+VIgLQzKm+LV4Wc+OFbHIys+0saQUhItKO0/CsXGc8R314 +jdN5UsZk/MUdPPAs+6OCr8d3PpJvR6IST76TtN8aDjSS9T6em7dwdGFEwCGww3Jc +xrAkvvUmSlscz+rnvHA5DYQGK6NXLenB40sVQVfch1r1VqwvlzA0u7OovjwM8+7u ++DaBQ0YejbdnC7yfeE91LmZkG6jRKfvTJkv18tjNsgZsVmM13xzP67fCFIB9M+lN +t9zEldGKHVwm+06FHIWJsBDRgrquNb9xd1vgHHeIbJvKf+LqZhVrbKVEneG34Km+ +ndtb+mvcGc0fOoMU9lYrFaxAWl8oU9BchC9IyjcPZB445R+AhfTuoHSUViSCo6IO +TG0hQsJuNoKmDAU8l5sTsiFXuXBOo1wK8gTkRnhZHduZrZIjJXvT7efz1knLQ6eG +prZHf4CtbgHyAe2XZabetWtCsFcPbOjC7ezNK57UvVH98h2GkckxOM00BESMCTee +kYy7uG0v0rrajzHY1wARAQABiQIlBBgBCgAPBQJW4HonAhsMBQkHKygAAAoJECO1 +2++U1NgdyAsQAKZUVA6pY225BASkeNiW31L7K4VeRYpAdFkiRex2zQFtj9Vovfi1 +JeTs0fRm35dUsQraf1bkhsjEdPVZ3gD324/baauFO04KX+soyQvK/tUq8KO+5ALt +Ul5aAljuSwxfJWFpApv+Mbf7gOjm+77jirs7pgG/gCow/mkRlmKTwAmn2DXjkckC +2EH0mqmh5pdoNWKO7WeTFFbUmESsPcnB2FwTpEjHFvgHll+rmKpXZTgFYN4dDhhm +HsL/SCf/Nw+YIsuvErQ9TJVdJDLG8ZYatruk7dZZMPtFxvxM1Q36gDIpPEOKPkvm +dMXg6jHaIdYIaoMpzXFaXsQMdRuMtzbcA+CdwXVY55qGLtfmM/QuEiIJdDeeh7iB ++VAMyEFOOpi8IFhixaeMoZAmrKDqOkzPcMJVklLYq8N+b9p5JszYNwZEbpyWCACM +6K+iJzlWzW/OPZttGLJBgYuSYIJIuG80Cx5m5m1e5RAgQ1iT8nbfrS+gYttwP48J +V7SXQg7QugxG9l1vlK4VjnXiOFulJ7V0e/VyUBpJp3qHcCxFq3RnxVwlIqKZh+jm +Q1bk0H0Xodd27nQITfDP5ullByGW2Jrjs6SsXeR3jl9+t0XQfInU1L9d/wSOkMjL +9IMUt06lV4vB/WP2xioqLZiZ4eAi0E+lWkFxjZsgNs2xbOAYRThMB8a5 +=W1Ri +-----END PGP PUBLIC KEY BLOCK----- +``` +
diff --git a/SUPPORT.md b/.github/SUPPORT.md similarity index 100% rename from SUPPORT.md rename to .github/SUPPORT.md diff --git a/.github/workflows/triageBugs.yml b/.github/workflows/triageBugs.yml index f3354fb1..5f18126c 100644 --- a/.github/workflows/triageBugs.yml +++ b/.github/workflows/triageBugs.yml @@ -6,20 +6,33 @@ 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, '') - || !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._ \ No newline at end of file + _This decision was made by a bot. If you think the bot is wrong, let us know and we'll reopen this issue._ + diff --git a/.gitignore b/.gitignore index 80427507..a18d2645 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,3 @@ -secrets.properties - ###IntelliJ### *.iml diff --git a/README.md b/README.md index 24d0ac6d..48aafde9 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![Twitter](https://img.shields.io/badge/twitter-@Cryptomator-blue.svg?style=flat)](http://twitter.com/Cryptomator) [![Community](https://img.shields.io/badge/help-Community-orange.svg)](https://community.cryptomator.org) [![Documentation](https://img.shields.io/badge/help-Docs-orange.svg)](https://docs.cryptomator.org) +[![Crowdin](https://badges.crowdin.net/cryptomator-android/localized.svg)](https://crowdin.com/project/cryptomator-android) Cryptomator offers multi-platform transparent client-side encryption of your files in the cloud. @@ -24,10 +25,22 @@ Cryptomator for Android is currently available in the following distribution ch ``` git submodule init && git submodule update // (not necessary if cloned using --recurse-submodules) -./gradlew assembleLicenseDebug +./gradlew assembleApkstoreDebug ``` -Before connecting to Onedrive or Dropbox you have to enter valid API keys in [secrets.properties](https://github.com/cryptomator/android/blob/master/secrets.properties). +Before connecting to OneDrive or Dropbox you have to provide valid API keys using environment variables: +For build type + +* **release**: `DROPBOX_API_KEY` or `ONEDRIVE_API_KEY` and `ONEDRIVE_API_REDIRCT_URI` +* **debug**: `DROPBOX_API_KEY_DEBUG` or `ONEDRIVE_API_KEY_DEBUG` and `ONEDRIVE_API_REDIRCT_URI_DEBUG` + +## Contributing to Cryptomator for Android + +Please read our [contribution guide](.github/CONTRIBUTING.md), if you would like to report a bug, ask a question, translate the app or help us with coding. + +## Code of Conduct + +Help us keep Cryptomator open and inclusive. Please read and follow our [Code of Conduct](.github/CODE_OF_CONDUCT.md). ## License diff --git a/build.gradle b/build.gradle index 87f09f0c..10bcf17f 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:4.1.1' + classpath 'com.android.tools.build:gradle:4.1.2' classpath 'org.greenrobot:greendao-gradle-plugin:3.3.0' classpath 'com.fernandocejas.frodo:frodo-plugin:0.8.3' classpath 'com.vanniktech:gradle-android-junit-jacoco-plugin:0.16.0' @@ -42,7 +42,7 @@ allprojects { ext { androidApplicationId = 'org.cryptomator' androidVersionCode = getVersionCode() - androidVersionName = '1.5.11-SNAPSHOT' + androidVersionName = '1.5.11' } repositories { mavenCentral() diff --git a/buildsystem/dependencies.gradle b/buildsystem/dependencies.gradle index 2d941c03..8a95adc0 100644 --- a/buildsystem/dependencies.gradle +++ b/buildsystem/dependencies.gradle @@ -1,154 +1,155 @@ allprojects { - repositories { - jcenter() - } + repositories { + jcenter() + } } ext { - androidBuildToolsVersion = "29.0.2" - androidMinSdkVersion = 23 - androidTargetSdkVersion = 29 - androidCompileSdkVersion = 29 + androidBuildToolsVersion = "29.0.2" + androidMinSdkVersion = 23 + androidTargetSdkVersion = 29 + androidCompileSdkVersion = 29 - // android and java libs - androidVersion = '4.1.1.4' - multidexVersion = '2.0.1' - javaxAnnotationVersion = '1.0' + // android and java libs + androidVersion = '4.1.1.4' + multidexVersion = '2.0.1' + javaxAnnotationVersion = '1.0' - // support lib - androidSupportAnnotationsVersion = '1.1.0' - androidSupportAppcompatVersion = '1.2.0' // check https://stackoverflow.com/questions/41025200/android-view-inflateexception-error-inflating-class-android-webkit-webview/57968071#57968071 !!!!!! - androidSupportDesignVersion = '1.2.1' + // support lib + androidSupportAnnotationsVersion = '1.1.0' + androidSupportAppcompatVersion = '1.2.0' + // check https://stackoverflow.com/questions/41025200/android-view-inflateexception-error-inflating-class-android-webkit-webview/57968071#57968071 !!!!!! + androidSupportDesignVersion = '1.2.1' - // app frameworks and utilities + // app frameworks and utilities - rxJavaVersion = '2.2.20' - rxAndroidVersion = '2.1.1' - rxBindingVersion = '2.2.0' + rxJavaVersion = '2.2.20' + rxAndroidVersion = '2.1.1' + rxBindingVersion = '2.2.0' - daggerVersion = '2.30.1' + daggerVersion = '2.31.2' - gsonVersion = '2.8.6' + gsonVersion = '2.8.6' - okHttpVersion = '4.9.0' - okHttpDigestVersion = '2.5' + okHttpVersion = '4.9.0' + okHttpDigestVersion = '2.5' - velocityVersion = '1.7' + velocityVersion = '1.7' - timberVersion = '4.7.1' + timberVersion = '4.7.1' - zxcvbnVersion = '1.3.1' + zxcvbnVersion = '1.3.3' - scaleImageViewVersion = '3.10.0' + scaleImageViewVersion = '3.10.0' - lruFileCacheVersion = '1.0' + lruFileCacheVersion = '1.0' - // KEEP IN SYNC WITH GENERATOR VERSION IN root build.gradle - greenDaoVersion = '3.3.0' + // KEEP IN SYNC WITH GENERATOR VERSION IN root build.gradle + greenDaoVersion = '3.3.0' - // cloud provider libs + // cloud provider libs - // do not update to 1.4.0 until dropping minsdk 4.x - cryptolibVersion = '1.3.0' + // do not update to 1.4.0 until minsdk is 7.x (or desugaring works better) otherwise it will crash on 6.x + cryptolibVersion = '1.3.0' - dropboxVersion = '3.1.5' + dropboxVersion = '3.1.5' - googleApiServicesVersion = 'v3-rev197-1.25.0' - googlePlayServicesVersion = '19.0.0' - googleClientVersion = '1.31.1' + googleApiServicesVersion = 'v3-rev197-1.25.0' + googlePlayServicesVersion = '19.0.0' + googleClientVersion = '1.31.2' - msgraphVersion = '2.5.0' - msaAuthVersion = '0.10.0' + msgraphVersion = '2.5.0' + msaAuthVersion = '0.10.0' - commonsCodecVersion = '1.15' + commonsCodecVersion = '1.15' recyclerViewFastScrollVersion = '2.0.1' - // testing dependencies + // testing dependencies - jUnitVersion = '5.7.0' + jUnitVersion = '5.7.0' jUnit4Version = '4.13.1' - assertJVersion = '1.7.1' - mockitoVersion = '3.6.28' - mockitoInlineVersion = '3.6.28' - hamcrestVersion = '1.3' - dexmakerVersion = '1.0' - espressoVersion = '3.3.0' - testingSupportLibVersion = '0.1' - runnerVersion = '1.3.0' - rulesVersion = '1.3.0' - contributionVersion = '3.3.0' - uiautomatorVersion = '2.2.0' + assertJVersion = '1.7.1' + mockitoVersion = '3.7.7' + mockitoInlineVersion = '3.7.7' + hamcrestVersion = '1.3' + dexmakerVersion = '1.0' + espressoVersion = '3.3.0' + testingSupportLibVersion = '0.1' + runnerVersion = '1.3.0' + rulesVersion = '1.3.0' + contributionVersion = '3.3.0' + uiautomatorVersion = '2.2.0' - androidxCoreVersion = '1.3.2' - androidxFragmentVersion = '1.2.5' - androidxViewpagerVersion = '1.0.0' - androidxSwiperefreshVersion = '1.1.0' - androidxPreferenceVersion = '1.0.0' // 1.1.0 and 1.1.2 does have a bug with the text size - androidxRecyclerViewVersion = '1.1.0' - androidxDocumentfileVersion = '1.0.1' + androidxCoreVersion = '1.3.2' + androidxFragmentVersion = '1.2.5' + androidxViewpagerVersion = '1.0.0' + androidxSwiperefreshVersion = '1.1.0' + androidxPreferenceVersion = '1.0.0' // 1.1.0 and 1.1.2 does have a bug with the text size + androidxRecyclerViewVersion = '1.1.0' + androidxDocumentfileVersion = '1.0.1' androidxBiometricVersion = '1.0.1' androidxTestCoreVersion = '1.3.0' - jsonWebTokenApiVersion = '0.11.2' + jsonWebTokenApiVersion = '0.11.2' - dependencies = [ - android : "com.google.android:android:${androidVersion}", - androidAnnotations : "androidx.annotation:annotation:${androidSupportAnnotationsVersion}", - appcompat : "androidx.appcompat:appcompat:${androidSupportAppcompatVersion}", - androidxBiometric : "androidx.biometric:biometric:${androidxBiometricVersion}", + dependencies = [ + android : "com.google.android:android:${androidVersion}", + androidAnnotations : "androidx.annotation:annotation:${androidSupportAnnotationsVersion}", + appcompat : "androidx.appcompat:appcompat:${androidSupportAppcompatVersion}", + androidxBiometric : "androidx.biometric:biometric:${androidxBiometricVersion}", androidxCore : "androidx.core:core-ktx:${androidxCoreVersion}", - androidxFragment : "androidx.fragment:fragment-ktx:${androidxFragmentVersion}", - androidxViewpager : "androidx.viewpager:viewpager:${androidxViewpagerVersion}", - androidxSwiperefresh : "androidx.swiperefreshlayout:swiperefreshlayout:${androidxSwiperefreshVersion}", - androidxPreference : "androidx.preference:preference:${androidxPreferenceVersion}", - documentFile : "androidx.documentfile:documentfile:${androidxDocumentfileVersion}", - recyclerView : "androidx.recyclerview:recyclerview:${androidxRecyclerViewVersion}", + androidxFragment : "androidx.fragment:fragment-ktx:${androidxFragmentVersion}", + androidxViewpager : "androidx.viewpager:viewpager:${androidxViewpagerVersion}", + androidxSwiperefresh : "androidx.swiperefreshlayout:swiperefreshlayout:${androidxSwiperefreshVersion}", + androidxPreference : "androidx.preference:preference:${androidxPreferenceVersion}", + documentFile : "androidx.documentfile:documentfile:${androidxDocumentfileVersion}", + recyclerView : "androidx.recyclerview:recyclerview:${androidxRecyclerViewVersion}", androidxTestCore : "androidx.test:core:${androidxTestCoreVersion}", - commonsCodec : "commons-codec:commons-codec:${commonsCodecVersion}", - cryptolib : "org.cryptomator:cryptolib:${cryptolibVersion}", - dagger : "com.google.dagger:dagger:${daggerVersion}", - daggerCompiler : "com.google.dagger:dagger-compiler:${daggerVersion}", - design : "com.google.android.material:material:${androidSupportDesignVersion}", - dropbox : "com.dropbox.core:dropbox-core-sdk:${dropboxVersion}", - espresso : "androidx.test.espresso:espresso-core:${espressoVersion}", - googleApiClientAndroid: "com.google.api-client:google-api-client-android:${googleClientVersion}", - googleApiServicesDrive: "com.google.apis:google-api-services-drive:${googleApiServicesVersion}", - googlePlayServicesAuth: "com.google.android.gms:play-services-auth:${googlePlayServicesVersion}", - greenDao : "org.greenrobot:greendao:${greenDaoVersion}", - gson : "com.google.code.gson:gson:${gsonVersion}", - hamcrest : "org.hamcrest:hamcrest-all:${hamcrestVersion}", - javaxAnnotation : "javax.annotation:jsr250-api:${javaxAnnotationVersion}", - junit : "org.junit.jupiter:junit-jupiter:${jUnitVersion}", + commonsCodec : "commons-codec:commons-codec:${commonsCodecVersion}", + cryptolib : "org.cryptomator:cryptolib:${cryptolibVersion}", + dagger : "com.google.dagger:dagger:${daggerVersion}", + daggerCompiler : "com.google.dagger:dagger-compiler:${daggerVersion}", + design : "com.google.android.material:material:${androidSupportDesignVersion}", + dropbox : "com.dropbox.core:dropbox-core-sdk:${dropboxVersion}", + espresso : "androidx.test.espresso:espresso-core:${espressoVersion}", + googleApiClientAndroid: "com.google.api-client:google-api-client-android:${googleClientVersion}", + googleApiServicesDrive: "com.google.apis:google-api-services-drive:${googleApiServicesVersion}", + googlePlayServicesAuth: "com.google.android.gms:play-services-auth:${googlePlayServicesVersion}", + greenDao : "org.greenrobot:greendao:${greenDaoVersion}", + gson : "com.google.code.gson:gson:${gsonVersion}", + hamcrest : "org.hamcrest:hamcrest-all:${hamcrestVersion}", + javaxAnnotation : "javax.annotation:jsr250-api:${javaxAnnotationVersion}", + junit : "org.junit.jupiter:junit-jupiter:${jUnitVersion}", junitApi : "org.junit.jupiter:junit-jupiter-api:${jUnitVersion}", junitEngine : "org.junit.jupiter:junit-jupiter-engine:${jUnitVersion}", junitParams : "org.junit.jupiter:junit-jupiter-params:${jUnitVersion}", junit4 : "org.junit.jupiter:junit-jupiter:${jUnit4Version}", junit4Engine : "org.junit.vintage:junit-vintage-engine:${jUnitVersion}", - msgraph : "com.microsoft.graph:microsoft-graph:${msgraphVersion}", - msaAuth : "com.microsoft.graph:msa-auth-for-android-adapter:${msaAuthVersion}", - mockito : "org.mockito:mockito-core:${mockitoVersion}", + msgraph : "com.microsoft.graph:microsoft-graph:${msgraphVersion}", + msaAuth : "com.microsoft.graph:msa-auth-for-android-adapter:${msaAuthVersion}", + mockito : "org.mockito:mockito-core:${mockitoVersion}", mockitoInline : "org.mockito:mockito-inline:${mockitoInlineVersion}", - multidex : "androidx.multidex:multidex:${multidexVersion}", - okHttp : "com.squareup.okhttp3:okhttp:${okHttpVersion}", - okHttpDigest : "com.burgstaller:okhttp-digest:${okHttpDigestVersion}", + multidex : "androidx.multidex:multidex:${multidexVersion}", + okHttp : "com.squareup.okhttp3:okhttp:${okHttpVersion}", + okHttpDigest : "com.burgstaller:okhttp-digest:${okHttpDigestVersion}", recyclerViewFastScroll: "com.simplecityapps:recyclerview-fastscroll:${recyclerViewFastScrollVersion}", rxJava : "io.reactivex.rxjava2:rxjava:${rxJavaVersion}", - rxAndroid : "io.reactivex.rxjava2:rxandroid:${rxAndroidVersion}", - rxBinding : "com.jakewharton.rxbinding2:rxbinding:${rxBindingVersion}", - testingSupportLib : "com.android.support.test:testing-support-lib:${testingSupportLibVersion}", - timber : "com.jakewharton.timber:timber:${timberVersion}", - velocity : "org.apache.velocity:velocity:${velocityVersion}", - runner : "androidx.test:runner:${runnerVersion}", - rules : "androidx.test:rules:${rulesVersion}", - contribution : "androidx.test.espresso:espresso-contrib:${contributionVersion}", - uiAutomator : "androidx.test.uiautomator:uiautomator:${uiautomatorVersion}", - zxcvbn : "com.nulab-inc:zxcvbn:${zxcvbnVersion}", - scaleImageView : "com.davemorrissey.labs:subsampling-scale-image-view:${scaleImageViewVersion}", - lruFileCache : "com.tomclaw.cache:cache:${lruFileCacheVersion}", - jsonWebTokenApi : "io.jsonwebtoken:jjwt-api:${jsonWebTokenApiVersion}", - jsonWebTokenImpl : "io.jsonwebtoken:jjwt-impl:${jsonWebTokenApiVersion}", - jsonWebTokenJson : "io.jsonwebtoken:jjwt-orgjson:${jsonWebTokenApiVersion}" - ] + rxAndroid : "io.reactivex.rxjava2:rxandroid:${rxAndroidVersion}", + rxBinding : "com.jakewharton.rxbinding2:rxbinding:${rxBindingVersion}", + testingSupportLib : "com.android.support.test:testing-support-lib:${testingSupportLibVersion}", + timber : "com.jakewharton.timber:timber:${timberVersion}", + velocity : "org.apache.velocity:velocity:${velocityVersion}", + runner : "androidx.test:runner:${runnerVersion}", + rules : "androidx.test:rules:${rulesVersion}", + contribution : "androidx.test.espresso:espresso-contrib:${contributionVersion}", + uiAutomator : "androidx.test.uiautomator:uiautomator:${uiautomatorVersion}", + zxcvbn : "com.nulab-inc:zxcvbn:${zxcvbnVersion}", + scaleImageView : "com.davemorrissey.labs:subsampling-scale-image-view:${scaleImageViewVersion}", + lruFileCache : "com.tomclaw.cache:cache:${lruFileCacheVersion}", + jsonWebTokenApi : "io.jsonwebtoken:jjwt-api:${jsonWebTokenApiVersion}", + jsonWebTokenImpl : "io.jsonwebtoken:jjwt-impl:${jsonWebTokenApiVersion}", + jsonWebTokenJson : "io.jsonwebtoken:jjwt-orgjson:${jsonWebTokenApiVersion}" + ] } diff --git a/data/build.gradle b/data/build.gradle index 3608ab82..d9b3ca1c 100644 --- a/data/build.gradle +++ b/data/build.gradle @@ -17,7 +17,6 @@ android { buildConfigField 'int', 'VERSION_CODE', "${globalConfiguration["androidVersionCode"]}" buildConfigField "String", "VERSION_NAME", "\"${globalConfiguration["androidVersionName"]}\"" - buildConfigField "String", "ONEDRIVE_API_KEY", "\"" + getApiKey('ONEDRIVE_API_KEY') + "\"" } compileOptions { @@ -31,6 +30,18 @@ android { ignoreWarnings true } + buildTypes { + release { + buildConfigField "String", "ONEDRIVE_API_KEY", "\"" + getApiKey('ONEDRIVE_API_KEY') + "\"" + buildConfigField "String", "ONEDRIVE_API_REDIRCT_URI", "\"" + getApiKey('ONEDRIVE_API_REDIRCT_URI') + "\"" + } + + debug { + buildConfigField "String", "ONEDRIVE_API_KEY", "\"" + getApiKey('ONEDRIVE_API_KEY_DEBUG') + "\"" + buildConfigField "String", "ONEDRIVE_API_REDIRCT_URI", "\"" + getApiKey('ONEDRIVE_API_REDIRCT_URI_DEBUG') + "\"" + } + } + flavorDimensions "version" productFlavors { @@ -38,9 +49,27 @@ android { dimension "version" } - license { + apkstore { dimension "version" } + + fdroid { + dimension "version" + } + } + + sourceSets { + playstore { + java.srcDirs = ['src/main/java', 'src/main/java/', 'src/notFoss/java', 'src/notFoss/java/'] + } + + apkstore { + java.srcDirs = ['src/main/java', 'src/main/java/', 'src/notFoss/java', 'src/notFoss/java/'] + } + + fdroid { + java.srcDirs = ['src/main/java', 'src/main/java/', 'src/foss/java', 'src/foss/java/'] + } } } @@ -70,17 +99,29 @@ dependencies { implementation dependencies.dagger // cloud implementation dependencies.dropbox - implementation dependencies.googlePlayServicesAuth - implementation(dependencies.googleApiServicesDrive) { - exclude module: 'guava-jdk5' - exclude module: 'httpclient' - } - implementation(dependencies.googleApiClientAndroid) { - exclude module: 'guava-jdk5' - exclude module: 'httpclient' - } implementation dependencies.msgraph + playstoreImplementation dependencies.googlePlayServicesAuth + apkstoreImplementation dependencies.googlePlayServicesAuth + + playstoreImplementation(dependencies.googleApiServicesDrive) { + exclude module: 'guava-jdk5' + exclude module: 'httpclient' + } + apkstoreImplementation(dependencies.googleApiServicesDrive) { + exclude module: 'guava-jdk5' + exclude module: 'httpclient' + } + + playstoreImplementation(dependencies.googleApiClientAndroid) { + exclude module: 'guava-jdk5' + exclude module: 'httpclient' + } + apkstoreImplementation(dependencies.googleApiClientAndroid) { + exclude module: 'guava-jdk5' + exclude module: 'httpclient' + } + // rest implementation dependencies.rxJava implementation dependencies.rxAndroid @@ -116,7 +157,5 @@ configurations { } static def getApiKey(key) { - Properties props = new Properties() - props.load(new FileInputStream(new File('secrets.properties'))) - return props[key] + return System.getenv().getOrDefault(key, "") } diff --git a/data/src/foss/java/org/cryptomator/data/cloud/CloudContentRepositoryFactories.java b/data/src/foss/java/org/cryptomator/data/cloud/CloudContentRepositoryFactories.java new file mode 100644 index 00000000..277858d2 --- /dev/null +++ b/data/src/foss/java/org/cryptomator/data/cloud/CloudContentRepositoryFactories.java @@ -0,0 +1,42 @@ +package org.cryptomator.data.cloud; + +import org.cryptomator.data.cloud.crypto.CryptoCloudContentRepositoryFactory; +import org.cryptomator.data.cloud.dropbox.DropboxCloudContentRepositoryFactory; +import org.cryptomator.data.cloud.local.LocalStorageContentRepositoryFactory; +import org.cryptomator.data.cloud.onedrive.OnedriveCloudContentRepositoryFactory; +import org.cryptomator.data.cloud.webdav.WebDavCloudContentRepositoryFactory; +import org.cryptomator.data.repository.CloudContentRepositoryFactory; +import org.jetbrains.annotations.NotNull; + +import java.util.Iterator; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import static java.util.Arrays.asList; + +@Singleton +public class CloudContentRepositoryFactories implements Iterable { + + private final Iterable factories; + + @Inject + public CloudContentRepositoryFactories(DropboxCloudContentRepositoryFactory dropboxFactory, // + OnedriveCloudContentRepositoryFactory oneDriveFactory, // + CryptoCloudContentRepositoryFactory cryptoFactory, // + LocalStorageContentRepositoryFactory localStorageFactory, // + WebDavCloudContentRepositoryFactory webDavFactory) { + + factories = asList(dropboxFactory, // + oneDriveFactory, // + cryptoFactory, // + localStorageFactory, // + webDavFactory); + } + + @NotNull + @Override + public Iterator iterator() { + return factories.iterator(); + } +} diff --git a/data/src/main/java/org/cryptomator/data/cloud/onedrive/graph/MicrosoftOAuth2Endpoint.java b/data/src/main/java/org/cryptomator/data/cloud/onedrive/graph/MicrosoftOAuth2Endpoint.java index 168bb6de..5adb24a9 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/onedrive/graph/MicrosoftOAuth2Endpoint.java +++ b/data/src/main/java/org/cryptomator/data/cloud/onedrive/graph/MicrosoftOAuth2Endpoint.java @@ -4,6 +4,8 @@ import android.net.Uri; import com.microsoft.services.msa.OAuthConfig; +import org.cryptomator.data.BuildConfig; + class MicrosoftOAuth2Endpoint implements OAuthConfig { /** * The current instance of this class @@ -12,7 +14,7 @@ class MicrosoftOAuth2Endpoint implements OAuthConfig { /** * The current instance of this class - * + * * @return The instance */ static MicrosoftOAuth2Endpoint getInstance() { @@ -26,7 +28,7 @@ class MicrosoftOAuth2Endpoint implements OAuthConfig { @Override public Uri getDesktopUri() { - return Uri.parse("urn:ietf:wg:oauth:2.0:oob"); + return Uri.parse(BuildConfig.ONEDRIVE_API_REDIRCT_URI); } @Override diff --git a/data/src/main/java/org/cryptomator/data/cloud/CloudContentRepositoryFactories.java b/data/src/notFoss/java/org/cryptomator/data/cloud/CloudContentRepositoryFactories.java similarity index 100% rename from data/src/main/java/org/cryptomator/data/cloud/CloudContentRepositoryFactories.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/CloudContentRepositoryFactories.java diff --git a/data/src/main/java/org/cryptomator/data/cloud/googledrive/FixedGoogleAccountCredential.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/FixedGoogleAccountCredential.java similarity index 100% rename from data/src/main/java/org/cryptomator/data/cloud/googledrive/FixedGoogleAccountCredential.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/FixedGoogleAccountCredential.java diff --git a/data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveClientFactory.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveClientFactory.java similarity index 78% rename from data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveClientFactory.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveClientFactory.java index 6775d7e8..02532be4 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveClientFactory.java +++ b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveClientFactory.java @@ -2,8 +2,8 @@ package org.cryptomator.data.cloud.googledrive; import android.content.Context; -import com.google.api.client.extensions.android.http.AndroidHttp; -import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.api.client.http.javanet.NetHttpTransport; +import com.google.api.client.json.gson.GsonFactory; import com.google.api.services.drive.Drive; import com.google.api.services.drive.DriveScopes; @@ -24,7 +24,7 @@ class GoogleDriveClientFactory { try { FixedGoogleAccountCredential credential = FixedGoogleAccountCredential.usingOAuth2(context, Collections.singleton(DriveScopes.DRIVE)); credential.setAccountName(accountName); - return new Drive.Builder(AndroidHttp.newCompatibleTransport(), JacksonFactory.getDefaultInstance(), credential) // + return new Drive.Builder(new NetHttpTransport(), GsonFactory.getDefaultInstance(), credential) // .setApplicationName("Cryptomator-Android/" + BuildConfig.VERSION_NAME) // .build(); } catch (Exception e) { diff --git a/data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudContentRepository.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudContentRepository.java similarity index 100% rename from data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudContentRepository.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudContentRepository.java diff --git a/data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudContentRepositoryFactory.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudContentRepositoryFactory.java similarity index 100% rename from data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudContentRepositoryFactory.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudContentRepositoryFactory.java diff --git a/data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudNodeFactory.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudNodeFactory.java similarity index 100% rename from data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudNodeFactory.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudNodeFactory.java diff --git a/data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveFile.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveFile.java similarity index 100% rename from data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveFile.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveFile.java diff --git a/data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveFolder.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveFolder.java similarity index 100% rename from data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveFolder.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveFolder.java diff --git a/data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveIdCache.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveIdCache.java similarity index 100% rename from data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveIdCache.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveIdCache.java diff --git a/data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveIdCloudNode.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveIdCloudNode.java similarity index 100% rename from data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveIdCloudNode.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveIdCloudNode.java diff --git a/data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveImpl.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveImpl.java similarity index 99% rename from data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveImpl.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveImpl.java index 48df9744..0ccebe23 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveImpl.java +++ b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveImpl.java @@ -13,7 +13,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import org.cryptomator.data.util.TransferredBytesAwareGoogleContentInputStream; import org.cryptomator.data.util.TransferredBytesAwareOutputStream; import org.cryptomator.domain.CloudNode; import org.cryptomator.domain.GoogleDriveCloud; diff --git a/data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveNode.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveNode.java similarity index 100% rename from data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveNode.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveNode.java diff --git a/data/src/main/java/org/cryptomator/data/cloud/googledrive/RootGoogleDriveFolder.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/RootGoogleDriveFolder.java similarity index 100% rename from data/src/main/java/org/cryptomator/data/cloud/googledrive/RootGoogleDriveFolder.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/RootGoogleDriveFolder.java diff --git a/data/src/main/java/org/cryptomator/data/util/TransferredBytesAwareGoogleContentInputStream.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/TransferredBytesAwareGoogleContentInputStream.java similarity index 90% rename from data/src/main/java/org/cryptomator/data/util/TransferredBytesAwareGoogleContentInputStream.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/TransferredBytesAwareGoogleContentInputStream.java index f35f4adb..2648efcd 100644 --- a/data/src/main/java/org/cryptomator/data/util/TransferredBytesAwareGoogleContentInputStream.java +++ b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/TransferredBytesAwareGoogleContentInputStream.java @@ -1,7 +1,9 @@ -package org.cryptomator.data.util; +package org.cryptomator.data.cloud.googledrive; import com.google.api.client.http.AbstractInputStreamContent; +import org.cryptomator.data.util.TransferredBytesAwareInputStream; + import java.io.Closeable; import java.io.IOException; import java.io.InputStream; diff --git a/demo-mode.sh b/demo-mode.sh new file mode 100755 index 00000000..9f70ba43 --- /dev/null +++ b/demo-mode.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +adb shell settings put global sysui_demo_allowed 1 + +adb shell am broadcast -a com.android.systemui.demo -e command clock -e hhmm 1200 +adb shell am broadcast -a com.android.systemui.demo -e command network -e mobile show -e level 4 -e datatype false +adb shell am broadcast -a com.android.systemui.demo -e command notifications -e visible false +adb shell am broadcast -a com.android.systemui.demo -e command battery -e plugged false -e level 100 diff --git a/generator/src/main/java/org/cryptomator/generator/IntentProcessor.java b/generator/src/main/java/org/cryptomator/generator/IntentProcessor.java index 87dc3dbd..3c25d90d 100644 --- a/generator/src/main/java/org/cryptomator/generator/IntentProcessor.java +++ b/generator/src/main/java/org/cryptomator/generator/IntentProcessor.java @@ -34,6 +34,7 @@ public class IntentProcessor extends BaseProcessor { intentsModelBuilder.add(generateIntentReader((TypeElement) element)); } if (!intentAnnotatedElements.isEmpty()) { + intentAnnotatedElements.sort((e1, e2) -> e1.getSimpleName().toString().compareTo(e2.getSimpleName().toString())); generateIntents(intentsModelBuilder.build(), intentAnnotatedElements); } } diff --git a/generator/src/main/java/org/cryptomator/generator/model/ActivitiesModel.java b/generator/src/main/java/org/cryptomator/generator/model/ActivitiesModel.java index 4a8187e6..d594ac97 100644 --- a/generator/src/main/java/org/cryptomator/generator/model/ActivitiesModel.java +++ b/generator/src/main/java/org/cryptomator/generator/model/ActivitiesModel.java @@ -1,21 +1,21 @@ package org.cryptomator.generator.model; -import java.util.ArrayList; -import java.util.List; +import java.util.Set; +import java.util.TreeSet; public class ActivitiesModel { - private final List activities; + private final Set activities; public static ActivitiesModel.Builder builder() { return new Builder(); } - private ActivitiesModel(List activities) { + private ActivitiesModel(Set activities) { this.activities = activities; } - public List getActivities() { + public Set getActivities() { return activities; } @@ -29,7 +29,7 @@ public class ActivitiesModel { public static class Builder { - private final List activities = new ArrayList<>(); + private final Set activities = new TreeSet<>(); private Builder() { } diff --git a/generator/src/main/java/org/cryptomator/generator/model/ActivityModel.java b/generator/src/main/java/org/cryptomator/generator/model/ActivityModel.java index c565f05a..4aac9b55 100644 --- a/generator/src/main/java/org/cryptomator/generator/model/ActivityModel.java +++ b/generator/src/main/java/org/cryptomator/generator/model/ActivityModel.java @@ -12,7 +12,7 @@ import javax.lang.model.element.TypeElement; import static java.util.stream.Collectors.toList; -public class ActivityModel { +public class ActivityModel implements Comparable { private final String qualifiedName; @@ -128,4 +128,9 @@ public class ActivityModel { public String getPresenterIntentFieldName() { return presenterIntentFieldName; } + + @Override + public int compareTo(ActivityModel activityModel) { + return this.qualifiedName.compareTo(activityModel.qualifiedName); + } } diff --git a/generator/src/main/java/org/cryptomator/generator/model/FragmentModel.java b/generator/src/main/java/org/cryptomator/generator/model/FragmentModel.java index b7f55631..d1d58aeb 100644 --- a/generator/src/main/java/org/cryptomator/generator/model/FragmentModel.java +++ b/generator/src/main/java/org/cryptomator/generator/model/FragmentModel.java @@ -6,7 +6,7 @@ import org.cryptomator.generator.utils.Type; import java.util.Optional; -public class FragmentModel { +public class FragmentModel implements Comparable { private final String qualifiedName; @@ -45,4 +45,9 @@ public class FragmentModel { public boolean isHasPresenter() { return hasPresenter; } + + @Override + public int compareTo(FragmentModel fragmentModel) { + return this.qualifiedName.compareTo(fragmentModel.qualifiedName); + } } diff --git a/generator/src/main/java/org/cryptomator/generator/model/FragmentsModel.java b/generator/src/main/java/org/cryptomator/generator/model/FragmentsModel.java index 7ca076f6..b4864115 100644 --- a/generator/src/main/java/org/cryptomator/generator/model/FragmentsModel.java +++ b/generator/src/main/java/org/cryptomator/generator/model/FragmentsModel.java @@ -1,21 +1,21 @@ package org.cryptomator.generator.model; -import java.util.ArrayList; -import java.util.List; +import java.util.Set; +import java.util.TreeSet; public class FragmentsModel { - private final List fragments; + private final Set fragments; public static FragmentsModel.Builder builder() { return new Builder(); } - private FragmentsModel(List fragments) { + private FragmentsModel(Set fragments) { this.fragments = fragments; } - public List getFragments() { + public Set getFragments() { return fragments; } @@ -29,7 +29,7 @@ public class FragmentsModel { public static class Builder { - private final List fragments = new ArrayList<>(); + private final Set fragments = new TreeSet<>(); private Builder() { } diff --git a/generator/src/main/java/org/cryptomator/generator/model/InstanceStateModel.java b/generator/src/main/java/org/cryptomator/generator/model/InstanceStateModel.java index 2e0f3f53..4d18696e 100644 --- a/generator/src/main/java/org/cryptomator/generator/model/InstanceStateModel.java +++ b/generator/src/main/java/org/cryptomator/generator/model/InstanceStateModel.java @@ -4,18 +4,18 @@ import org.cryptomator.generator.ProcessorException; import org.cryptomator.generator.utils.Field; import org.cryptomator.generator.utils.Type; -import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; -import java.util.List; import java.util.Map; +import java.util.SortedSet; +import java.util.TreeMap; +import java.util.TreeSet; import javax.lang.model.element.Element; public class InstanceStateModel { private final String javaPackage; - private final Map types = new HashMap<>(); + private final Map types = new TreeMap<>(); public InstanceStateModel(String javaPackage) { this.javaPackage = javaPackage; @@ -47,7 +47,7 @@ public class InstanceStateModel { public static class InstanceStateType { - private final List fields = new ArrayList<>(); + private final SortedSet fields = new TreeSet<>(); private final String qualifiedName; public InstanceStateType(Type type) { @@ -62,12 +62,12 @@ public class InstanceStateModel { return qualifiedName; } - public List getFields() { + public SortedSet getFields() { return fields; } } - public static class InstanceStateField { + public static class InstanceStateField implements Comparable { private static int nextBundleKey = 0; @@ -142,6 +142,10 @@ public class InstanceStateModel { return field.element(); } + @Override + public int compareTo(InstanceStateField instanceStateField) { + return this.bundleKey.compareTo(instanceStateField.bundleKey); + } } } diff --git a/generator/src/main/java/org/cryptomator/generator/model/InstanceStatesModel.java b/generator/src/main/java/org/cryptomator/generator/model/InstanceStatesModel.java index 41703b5b..6b628a5e 100644 --- a/generator/src/main/java/org/cryptomator/generator/model/InstanceStatesModel.java +++ b/generator/src/main/java/org/cryptomator/generator/model/InstanceStatesModel.java @@ -2,13 +2,13 @@ package org.cryptomator.generator.model; import org.cryptomator.generator.utils.Field; -import java.util.HashMap; import java.util.Map; +import java.util.TreeMap; import java.util.stream.Stream; public class InstanceStatesModel { - private final Map instanceStatesByPackage = new HashMap<>(); + private final Map instanceStatesByPackage = new TreeMap<>(); public void add(Field field) { String packageName = field.declaringType().packageName(); diff --git a/generator/src/main/java/org/cryptomator/generator/model/IntentBuilderModel.java b/generator/src/main/java/org/cryptomator/generator/model/IntentBuilderModel.java index e0c468cb..019c159b 100644 --- a/generator/src/main/java/org/cryptomator/generator/model/IntentBuilderModel.java +++ b/generator/src/main/java/org/cryptomator/generator/model/IntentBuilderModel.java @@ -3,9 +3,12 @@ package org.cryptomator.generator.model; import org.cryptomator.generator.Intent; import org.cryptomator.generator.Optional; -import java.util.List; +import java.util.Comparator; import java.util.Map; +import java.util.Set; +import java.util.TreeSet; import java.util.function.Predicate; +import java.util.stream.Collectors; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationValue; @@ -14,16 +17,15 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.type.DeclaredType; import static java.lang.Character.toLowerCase; -import static java.util.stream.Collectors.toList; -public class IntentBuilderModel { +public class IntentBuilderModel implements Comparable { private final String javaPackage; private final String className; private final String targetActivity; private final String targetActivitySimpleName; private final String buildMethodName; - private final List parameters; + private final Set parameters; public IntentBuilderModel(TypeElement type) { this.javaPackage = javaPackage(type); @@ -47,9 +49,21 @@ public class IntentBuilderModel { } private static String targetActivity(TypeElement type) { - return type.getAnnotationMirrors().stream().filter(is(Intent.class)).findFirst().get().getElementValues().entrySet().stream().map(entry -> (Map.Entry) entry) - .filter(entry -> "value".equals(entry.getKey().getSimpleName().toString())).map(Map.Entry::getValue).map(AnnotationValue::getValue).map(DeclaredType.class::cast).map(DeclaredType::asElement) - .map(TypeElement.class::cast).findFirst().get().getQualifiedName().toString(); + return type // + .getAnnotationMirrors() // + .stream() // + .filter(is(Intent.class)) // + .findFirst().get().getElementValues().entrySet() // + .stream() // + .map(entry -> (Map.Entry) entry) // + .filter(entry -> "value".equals(entry.getKey().getSimpleName().toString())) // + .map(Map.Entry::getValue) // + .map(AnnotationValue::getValue) // + .map(DeclaredType.class::cast) // + .map(DeclaredType::asElement) // + .map(TypeElement.class::cast) // + .findFirst().get() // + .getQualifiedName().toString(); } private static Predicate is(Class type) { @@ -66,8 +80,14 @@ public class IntentBuilderModel { return toLowerCase(name.charAt(0)) + name.substring(1); } - private static List parameters(TypeElement type) { - return type.getEnclosedElements().stream().filter(ExecutableElement.class::isInstance).map(ExecutableElement.class::cast).map(ParameterModel::new).collect(toList()); + private static Set parameters(TypeElement type) { + return type // + .getEnclosedElements() // + .stream() // + .filter(ExecutableElement.class::isInstance) // + .map(ExecutableElement.class::cast) // + .map(ParameterModel::new) // + .collect(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(ParameterModel::getName)))); } private static String buildMethodName(TypeElement type) { @@ -101,6 +121,11 @@ public class IntentBuilderModel { return buildMethodName; } + @Override + public int compareTo(IntentBuilderModel intentBuilderModel) { + return (this.javaPackage + this.className).compareTo(intentBuilderModel.javaPackage + intentBuilderModel.className); + } + public static class ParameterModel { private final String nameWithFirstCharUppercase; diff --git a/generator/src/main/java/org/cryptomator/generator/model/IntentReaderModel.java b/generator/src/main/java/org/cryptomator/generator/model/IntentReaderModel.java index 62c59abf..7e3095dd 100644 --- a/generator/src/main/java/org/cryptomator/generator/model/IntentReaderModel.java +++ b/generator/src/main/java/org/cryptomator/generator/model/IntentReaderModel.java @@ -3,9 +3,12 @@ package org.cryptomator.generator.model; import org.cryptomator.generator.Intent; import org.cryptomator.generator.Optional; -import java.util.List; +import java.util.Comparator; import java.util.Map; +import java.util.Set; +import java.util.TreeSet; import java.util.function.Predicate; +import java.util.stream.Collectors; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationValue; @@ -13,16 +16,14 @@ import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import javax.lang.model.type.DeclaredType; -import static java.util.stream.Collectors.toList; - -public class IntentReaderModel { +public class IntentReaderModel implements Comparable { private final String javaPackage; private final String className; private final String targetActivity; private final String intentInterface; private final String readMethodName; - private final List parameters; + private final Set parameters; public IntentReaderModel(TypeElement type) { this.intentInterface = type.getQualifiedName().toString(); @@ -46,9 +47,22 @@ public class IntentReaderModel { } private static String targetActivity(TypeElement type) { - return type.getAnnotationMirrors().stream().filter(is(Intent.class)).findFirst().get().getElementValues().entrySet().stream().map(entry -> (Map.Entry) entry) - .filter(entry -> "value".equals(entry.getKey().getSimpleName().toString())).map(Map.Entry::getValue).map(AnnotationValue::getValue).map(DeclaredType.class::cast).map(DeclaredType::asElement) - .map(TypeElement.class::cast).findFirst().get().getQualifiedName().toString(); + return type // + .getAnnotationMirrors() // + .stream() // + .filter(is(Intent.class)) // + .findFirst().get().getElementValues().entrySet() // + .stream() // + .map(entry -> (Map.Entry) entry) // + .filter(entry -> "value".equals(entry.getKey().getSimpleName().toString())) // + .map(Map.Entry::getValue) // + .map(AnnotationValue::getValue) // + .map(DeclaredType.class::cast) // + .map(DeclaredType::asElement) // + .map(TypeElement.class::cast) // + .findFirst().get() // + .getQualifiedName() // + .toString(); } private static Predicate is(Class type) { @@ -59,8 +73,14 @@ public class IntentReaderModel { }; } - private static List parameters(TypeElement type) { - return type.getEnclosedElements().stream().filter(ExecutableElement.class::isInstance).map(ExecutableElement.class::cast).map(ParameterModel::new).collect(toList()); + private static Set parameters(TypeElement type) { + return type // + .getEnclosedElements() // + .stream() // + .filter(ExecutableElement.class::isInstance) // + .map(ExecutableElement.class::cast) // + .map(ParameterModel::new) // + .collect(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(ParameterModel::getName)))); } private static String readMethodName(TypeElement type) { @@ -94,6 +114,11 @@ public class IntentReaderModel { return readMethodName; } + @Override + public int compareTo(IntentReaderModel intentReaderModel) { + return (this.javaPackage + this.className).compareTo(intentReaderModel.javaPackage + intentReaderModel.className); + } + public static class ParameterModel { private final String name; diff --git a/generator/src/main/java/org/cryptomator/generator/model/IntentsModel.java b/generator/src/main/java/org/cryptomator/generator/model/IntentsModel.java index 13fe9129..af384366 100644 --- a/generator/src/main/java/org/cryptomator/generator/model/IntentsModel.java +++ b/generator/src/main/java/org/cryptomator/generator/model/IntentsModel.java @@ -1,27 +1,27 @@ package org.cryptomator.generator.model; -import java.util.ArrayList; -import java.util.List; +import java.util.Set; +import java.util.TreeSet; public class IntentsModel { - private final List builders; - private final List readers; + private final Set builders; + private final Set readers; public static IntentsModel.Builder builder() { return new Builder(); } - private IntentsModel(List builders, List readers) { + private IntentsModel(Set builders, Set readers) { this.builders = builders; this.readers = readers; } - public List getBuilders() { + public Set getBuilders() { return builders; } - public List getReaders() { + public Set getReaders() { return readers; } @@ -35,8 +35,8 @@ public class IntentsModel { public static class Builder { - private final List builders = new ArrayList<>(); - private final List readers = new ArrayList<>(); + private final Set builders = new TreeSet<>(); + private final Set readers = new TreeSet<>(); private Builder() { } diff --git a/generator/src/main/java/org/cryptomator/generator/utils/Method.java b/generator/src/main/java/org/cryptomator/generator/utils/Method.java index 4966517f..82eb56db 100644 --- a/generator/src/main/java/org/cryptomator/generator/utils/Method.java +++ b/generator/src/main/java/org/cryptomator/generator/utils/Method.java @@ -9,7 +9,7 @@ import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.type.TypeKind; -public class Method { +public class Method implements Comparable { private final Utils utils; private final ExecutableElement delegate; @@ -75,4 +75,9 @@ public class Method { public Type declaringType() { return new Type(utils, (TypeElement) delegate.getEnclosingElement()); } + + @Override + public int compareTo(Method method) { + return this.delegate.getSimpleName().toString().compareTo(method.delegate.getSimpleName().toString()); + } } diff --git a/generator/src/main/java/org/cryptomator/generator/utils/Type.java b/generator/src/main/java/org/cryptomator/generator/utils/Type.java index 61f115d4..884b1a9f 100644 --- a/generator/src/main/java/org/cryptomator/generator/utils/Type.java +++ b/generator/src/main/java/org/cryptomator/generator/utils/Type.java @@ -14,7 +14,7 @@ import static javax.lang.model.element.ElementKind.FIELD; import static javax.lang.model.type.TypeKind.ARRAY; import static javax.lang.model.type.TypeKind.NONE; -public class Type { +public class Type implements Comparable { private final TypeMirror mirror; private final Optional element; @@ -89,6 +89,7 @@ public class Type { return element // .map(type -> type.getEnclosedElements().stream() // .filter(ExecutableElement.class::isInstance) // + .sorted((e1, e2) -> e1.getSimpleName().toString().compareTo(e2.getSimpleName().toString())) // .map(ExecutableElement.class::cast) // .filter(Method::isConstructor) // .map(executableElement -> new Method(utils, executableElement))) @@ -99,20 +100,22 @@ public class Type { return element // .map(type -> type.getEnclosedElements().stream() // .filter(ExecutableElement.class::isInstance) // + .sorted((e1, e2) -> e1.getSimpleName().toString().compareTo(e2.getSimpleName().toString())) // .map(ExecutableElement.class::cast) // .filter(Method::isRegularMethod) // .map(executableElement -> new Method(utils, executableElement))) - .orElse(Stream.empty()); // + .orElse(Stream.empty()); } public Stream fields() { return element // .map(type -> type.getEnclosedElements().stream() // .filter(VariableElement.class::isInstance) // + .sorted((e1, e2) -> e1.getSimpleName().toString().compareTo(e2.getSimpleName().toString())) // .map(VariableElement.class::cast) // .filter(variable -> variable.getKind() == FIELD) // - .map(variableElement -> new Field(utils, variableElement))) - .orElse(Stream.empty()); // + .map(variableElement -> new Field(utils, variableElement))) // + .orElse(Stream.empty()); } @Override @@ -133,6 +136,11 @@ public class Type { return mirror.hashCode(); } + @Override + public int compareTo(Type type) { + return this.qualifiedName().compareTo(type.qualifiedName()); + } + public Optional enclosingType() { if (mirror instanceof DeclaredType) { return Optional.ofNullable(((DeclaredType) mirror).getEnclosingType()) // diff --git a/msa-auth-for-android b/msa-auth-for-android index eca34e84..fe4e0458 160000 --- a/msa-auth-for-android +++ b/msa-auth-for-android @@ -1 +1 @@ -Subproject commit eca34e843a1ca2d7953f0d7c22efe72572ce7dc1 +Subproject commit fe4e04589043cb18011cae80aec7eab09b46ed44 diff --git a/presentation/build.gradle b/presentation/build.gradle index 8eacd80d..81a1ea40 100644 --- a/presentation/build.gradle +++ b/presentation/build.gradle @@ -29,9 +29,6 @@ android { multiDexEnabled true testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' - - buildConfigField "String", "DROPBOX_API_KEY", "\"" + getApiKey('DROPBOX_API_KEY') + "\"" - manifestPlaceholders = [DROPBOX_API_KEY_DB: getApiKey('DROPBOX_API_KEY_DB')] } compileOptions { @@ -47,13 +44,32 @@ android { buildTypes { release { - minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + crunchPngs false + minifyEnabled false + shrinkResources false + useProguard false + + buildConfigField "String", "DROPBOX_API_KEY", "\"" + getApiKey('DROPBOX_API_KEY') + "\"" + manifestPlaceholders = [DROPBOX_API_KEY: getApiKey('DROPBOX_API_KEY')] + + resValue "string", "app_id", androidApplicationId } debug { signingConfig signingConfigs.debug + + crunchPngs false + minifyEnabled false + shrinkResources false testCoverageEnabled false + + buildConfigField "String", "DROPBOX_API_KEY", "\"" + getApiKey('DROPBOX_API_KEY_DEBUG') + "\"" + manifestPlaceholders = [DROPBOX_API_KEY: getApiKey('DROPBOX_API_KEY_DEBUG')] + + applicationIdSuffix ".debug" + versionNameSuffix '-DEBUG' + + resValue "string", "app_id", androidApplicationId + applicationIdSuffix } } @@ -64,9 +80,27 @@ android { dimension "version" } - license { + apkstore { dimension "version" } + + fdroid { + dimension "version" + } + } + + sourceSets { + playstore { + java.srcDirs = ['src/main/java', 'src/main/java/', 'src/notFoss/java', 'src/notFoss/java/'] + } + + apkstore { + java.srcDirs = ['src/main/java', 'src/main/java/', 'src/notFoss/java', 'src/notFoss/java/'] + } + + fdroid { + java.srcDirs = ['src/main/java', 'src/main/java/', 'src/foss/java', 'src/foss/java/'] + } } packagingOptions { @@ -106,11 +140,21 @@ dependencies { // cloud implementation dependencies.dropbox implementation dependencies.msgraph - implementation(dependencies.googleApiServicesDrive) { + + playstoreImplementation(dependencies.googleApiServicesDrive) { exclude module: 'guava-jdk5' exclude module: 'httpclient' } - implementation(dependencies.googleApiClientAndroid) { + apkstoreImplementation(dependencies.googleApiServicesDrive) { + exclude module: 'guava-jdk5' + exclude module: 'httpclient' + } + + playstoreImplementation(dependencies.googleApiClientAndroid) { + exclude module: 'guava-jdk5' + exclude module: 'httpclient' + } + apkstoreImplementation(dependencies.googleApiClientAndroid) { exclude module: 'guava-jdk5' exclude module: 'httpclient' } @@ -188,7 +232,5 @@ androidExtensions { } static def getApiKey(key) { - Properties props = new Properties() - props.load(new FileInputStream(new File('secrets.properties'))) - return props[key] + return System.getenv().getOrDefault(key, "") } diff --git a/presentation/proguard-rules.pro b/presentation/proguard-rules.pro deleted file mode 100644 index 8702417d..00000000 --- a/presentation/proguard-rules.pro +++ /dev/null @@ -1,81 +0,0 @@ --useuniqueclassmembernames - -# greenDAO 3, http://greenrobot.org/greendao/documentation/technical-faq --keepclassmembers class * extends org.greenrobot.greendao.AbstractDao { - public static java.lang.String TABLENAME; -} --keep class **$Properties {*;} --dontwarn org.greenrobot.greendao.database.** --dontwarn net.sqlcipher.database.** --dontwarn rx.** - -# RxJava, https://github.com/artem-zinnatullin/RxJavaProGuardRules/blob/master/rxjava-proguard-rules/proguard-rules.txt --dontwarn sun.misc.** --keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* { - long producerIndex; - long consumerIndex; -} --keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef { - rx.internal.util.atomic.LinkedQueueNode producerNode; -} --keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef { - rx.internal.util.atomic.LinkedQueueNode consumerNode; -} - -# Google API Client, https://github.com/google/google-api-java-client/blob/dev/google-api-client-assembly/proguard-google-api-client.txt --keepattributes Signature,RuntimeVisibleAnnotations,AnnotationDefault --keepclassmembers class * { - @com.google.api.client.util.Key ; -} --dontwarn com.google.api.client.extensions.android.** --dontwarn com.google.api.client.googleapis.extensions.android.** --dontwarn com.google.api.client.googleapis.testing.TestUtils --dontwarn com.google.android.gms.** - -# okhttp3 --dontwarn okhttp3.** --dontwarn okio.** - -# Others --dontwarn org.slf4j.** --dontwarn com.dropbox.core.** --dontwarn com.fernandocejas.frodo.core.** --dontwarn com.google.errorprone.annotations.** --dontwarn com.google.common.util.concurrent.FuturesGetChecked** --keepclassmembers class com.microsoft.graph.http.GraphServiceException { - int mResponseCode; -} --keep class com.nulabinc.zxcvbn.** - -# https://stackoverflow.com/a/47555897/1759462 --dontwarn afu.org.checkerframework.** --dontwarn org.checkerframework.** - -# https://github.com/microsoftgraph/msgraph-sdk-java/issues/258#issue-452030712 --keep class com.microsoft.** { *; } --keep class com.microsoft.** --keep interface com.microsoft.** { *; } --keepclasseswithmembernames class com.microsoft.** { *; } - --keep class com.sun.** { *; } --keep class com.sun.** --keep interface com.sun.** { *; } - -# https://github.com/jwtk/jjwt --keepattributes InnerClasses - --keep class io.jsonwebtoken.** { *; } --keepnames class io.jsonwebtoken.* { *; } --keepnames interface io.jsonwebtoken.* { *; } - --keep class org.bouncycastle.** { *; } --keepnames class org.bouncycastle.** { *; } --dontwarn org.bouncycastle.** - --keep class android.net.http.** { *; } --keep interface org.apache.** { *; } --keep enum org.apache.** { *; } --keep class org.apache.** { *; } --keep class org.apache.commons.** { *; } --keep class org.apache.http.** { *; } --keep class org.apache.harmony.** {*;} diff --git a/presentation/src/debug/res/values/strings.xml b/presentation/src/debug/res/values/strings.xml new file mode 100644 index 00000000..1ad426c7 --- /dev/null +++ b/presentation/src/debug/res/values/strings.xml @@ -0,0 +1,6 @@ + + + + Debug Cryptomator + + diff --git a/presentation/src/foss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt b/presentation/src/foss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt new file mode 100644 index 00000000..1c76fb07 --- /dev/null +++ b/presentation/src/foss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt @@ -0,0 +1,338 @@ +package org.cryptomator.presentation.presenter + +import android.Manifest +import android.accounts.AccountManager +import com.dropbox.core.android.Auth +import org.cryptomator.data.cloud.onedrive.OnedriveClientFactory +import org.cryptomator.data.cloud.onedrive.graph.ClientException +import org.cryptomator.data.cloud.onedrive.graph.ICallback +import org.cryptomator.data.util.X509CertificateHelper +import org.cryptomator.domain.* +import org.cryptomator.domain.di.PerView +import org.cryptomator.domain.exception.FatalBackendException +import org.cryptomator.domain.exception.NetworkConnectionException +import org.cryptomator.domain.exception.authentication.* +import org.cryptomator.domain.usecases.cloud.AddOrChangeCloudConnectionUseCase +import org.cryptomator.domain.usecases.cloud.GetUsernameUseCase +import org.cryptomator.generator.Callback +import org.cryptomator.presentation.BuildConfig +import org.cryptomator.presentation.R +import org.cryptomator.presentation.exception.ExceptionHandlers +import org.cryptomator.presentation.exception.PermissionNotGrantedException +import org.cryptomator.presentation.intent.AuthenticateCloudIntent +import org.cryptomator.presentation.model.* +import org.cryptomator.presentation.model.mappers.CloudModelMapper +import org.cryptomator.presentation.ui.activity.view.AuthenticateCloudView +import org.cryptomator.presentation.workflow.* +import org.cryptomator.util.ExceptionUtil +import org.cryptomator.util.crypto.CredentialCryptor +import timber.log.Timber +import java.security.cert.CertificateEncodingException +import java.security.cert.CertificateException +import java.security.cert.X509Certificate +import javax.inject.Inject + +@PerView +class AuthenticateCloudPresenter @Inject constructor( // + exceptionHandlers: ExceptionHandlers, // + private val cloudModelMapper: CloudModelMapper, // + private val addOrChangeCloudConnectionUseCase: AddOrChangeCloudConnectionUseCase, // + private val getUsernameUseCase: GetUsernameUseCase, // + private val addExistingVaultWorkflow: AddExistingVaultWorkflow, // + private val createNewVaultWorkflow: CreateNewVaultWorkflow) : Presenter(exceptionHandlers) { + + private val strategies = arrayOf( // + DropboxAuthStrategy(), // + OnedriveAuthStrategy(), // + WebDAVAuthStrategy(), // + LocalStorageAuthStrategy() // + ) + + override fun workflows(): Iterable> { + return listOf(createNewVaultWorkflow, addExistingVaultWorkflow) + } + + override fun resumed() { + val cloud = view?.intent()?.cloud() + val error = view?.intent()?.error() + handleNetworkConnectionExceptionIfRequired(error) + view?.intent()?.let { cloud?.let { cloud -> authStrategyFor(cloud).resumed(it) } } + } + + private fun handleNetworkConnectionExceptionIfRequired(error: AuthenticationException?) { + if (error != null && ExceptionUtil.contains(error, NetworkConnectionException::class.java)) { + view?.showMessage(R.string.error_no_network_connection) + finish() + } + } + + private fun authStrategyFor(cloud: CloudModel): AuthStrategy { + strategies.forEach { strategy -> + if (strategy.supports(cloud)) { + return strategy + } + } + return FailingAuthStrategy() + } + + private fun getUsernameAndSuceedAuthentication(cloud: Cloud) { + getUsernameUseCase.withCloud(cloud).run(object : DefaultResultHandler() { + override fun onSuccess(username: String) { + succeedAuthenticationWith(updateUsernameOf(cloud, username)) + } + + override fun onError(e: Throwable) { + super.onError(e) + finish() + } + }) + } + + private fun updateUsernameOf(cloud: Cloud, username: String): Cloud { + when (cloud.type()) { + CloudType.DROPBOX -> return DropboxCloud.aCopyOf(cloud as DropboxCloud).withUsername(username).build() + CloudType.ONEDRIVE -> return OnedriveCloud.aCopyOf(cloud as OnedriveCloud).withUsername(username).build() + } + throw IllegalStateException("Cloud " + cloud.type() + " is not supported") + } + + private fun succeedAuthenticationWith(cloud: Cloud) { + addOrChangeCloudConnectionUseCase // + .withCloud(cloud) // + .run(object : DefaultResultHandler() { + override fun onSuccess(void: Void?) { + finishWithResult(cloudModelMapper.toModel(cloud)) + } + + override fun onError(e: Throwable) { + super.onError(e) + finish() + } + }) + } + + private fun failAuthentication(cloudName: Int) { + view?.showMessage(String.format(getString(R.string.screen_authenticate_auth_authentication_failed), getString(cloudName))) + finish() + } + + private fun failAuthentication(error: PermissionNotGrantedException) { + finishWithResult(error) + } + + private inner class DropboxAuthStrategy : AuthStrategy { + private var authenticationStarted = false + override fun supports(cloud: CloudModel): Boolean { + return cloud.cloudType() == CloudTypeModel.DROPBOX + } + + override fun resumed(intent: AuthenticateCloudIntent) { + if (authenticationStarted) { + handleAuthenticationResult(intent.cloud()) + } else { + startAuthentication() + } + } + + private fun startAuthentication() { + showProgress(ProgressModel(ProgressStateModel.AUTHENTICATION)) + authenticationStarted = true + Auth.startOAuth2Authentication(context(), BuildConfig.DROPBOX_API_KEY) + view?.skipTransition() + } + + private fun handleAuthenticationResult(cloudModel: CloudModel) { + val authToken = Auth.getOAuth2Token() + if (authToken == null) { + failAuthentication(cloudModel.name()) + } else { + getUsernameAndSuceedAuthentication( // + DropboxCloud.aCopyOf(cloudModel.toCloud() as DropboxCloud) // + .withAccessToken(encrypt(authToken)) // + .build()) + } + } + } + + @Callback(dispatchResultOkOnly = false) + fun onUserRecoveryFinished(result: ActivityResult, cloud: CloudModel) { + if (result.isResultOk) { + succeedAuthenticationWith(cloud.toCloud()) + } else { + failAuthentication(cloud.name()) + } + } + + @Callback(dispatchResultOkOnly = false) + fun onGoogleDriveAuthenticated(result: ActivityResult, cloud: CloudModel) { + if (result.isResultOk) { + val accountName = result.intent()?.extras?.getString(AccountManager.KEY_ACCOUNT_NAME) + succeedAuthenticationWith(GoogleDriveCloud.aCopyOf(cloud.toCloud() as GoogleDriveCloud) // + .withUsername(accountName) // + .withAccessToken(accountName) // + .build()) + } else { + failAuthentication(cloud.name()) + } + } + + private inner class OnedriveAuthStrategy : AuthStrategy { + private var authenticationStarted = false + override fun supports(cloud: CloudModel): Boolean { + return cloud.cloudType() == CloudTypeModel.ONEDRIVE + } + + override fun resumed(intent: AuthenticateCloudIntent) { + if (!authenticationStarted) { + startAuthentication(intent.cloud()) + } + } + + private fun startAuthentication(cloud: CloudModel) { + authenticationStarted = true + val authenticationAdapter = OnedriveClientFactory.instance(context(), (cloud.toCloud() as OnedriveCloud).accessToken()).authenticationAdapter + authenticationAdapter.login(activity(), object : ICallback { + override fun success(accessToken: String?) { + if (accessToken == null) { + Timber.tag("AuthicateCloudPrester").e("Onedrive access token is empty") + failAuthentication(cloud.name()) + } else { + showProgress(ProgressModel(ProgressStateModel.AUTHENTICATION)) + handleAuthenticationResult(cloud, accessToken) + } + } + + override fun failure(ex: ClientException) { + Timber.tag("AuthicateCloudPrester").e(ex) + failAuthentication(cloud.name()) + } + }) + } + + private fun handleAuthenticationResult(cloud: CloudModel, accessToken: String) { + getUsernameAndSuceedAuthentication( // + OnedriveCloud.aCopyOf(cloud.toCloud() as OnedriveCloud) // + .withAccessToken(accessToken) // + .build()) + } + } + + private inner class WebDAVAuthStrategy : AuthStrategy { + override fun supports(cloud: CloudModel): Boolean { + return cloud.cloudType() == CloudTypeModel.WEBDAV + } + + override fun resumed(intent: AuthenticateCloudIntent) { + handleWebDavAuthenticationExceptionIfRequired(intent.cloud() as WebDavCloudModel, intent.error()) + } + + private fun handleWebDavAuthenticationExceptionIfRequired(cloud: WebDavCloudModel, e: AuthenticationException) { + Timber.tag("AuthicateCloudPrester").e(e) + when { + ExceptionUtil.contains(e, WrongCredentialsException::class.java) -> { + failAuthentication(cloud.name()) + } + ExceptionUtil.contains(e, WebDavCertificateUntrustedAuthenticationException::class.java) -> { + handleCertificateUntrustedExceptionIfRequired(cloud, e) + } + ExceptionUtil.contains(e, WebDavServerNotFoundException::class.java) -> { + view?.showMessage(R.string.error_server_not_found) + finish() + } + ExceptionUtil.contains(e, WebDavNotSupportedException::class.java) -> { + view?.showMessage(R.string.screen_cloud_error_webdav_not_supported) + finish() + } + } + } + + private fun handleCertificateUntrustedExceptionIfRequired(cloud: WebDavCloudModel, e: AuthenticationException) { + val untrustedException = ExceptionUtil.extract(e, WebDavCertificateUntrustedAuthenticationException::class.java) + try { + val certificate = X509CertificateHelper.convertFromPem(untrustedException.get().certificate) + view?.showUntrustedCertificateDialog(cloud.toCloud() as WebDavCloud, certificate) + } catch (ex: CertificateException) { + Timber.tag("AuthicateCloudPrester").e(ex) + throw FatalBackendException(ex) + } + } + } + + fun onAcceptWebDavCertificateClicked(cloud: WebDavCloud?, certificate: X509Certificate?) { + try { + val webDavCloudWithAcceptedCert = WebDavCloud.aCopyOf(cloud) // + .withCertificate(X509CertificateHelper.convertToPem(certificate)) // + .build() + finishWithResultAndExtra(cloudModelMapper.toModel(webDavCloudWithAcceptedCert), // + WEBDAV_ACCEPTED_UNTRUSTED_CERTIFICATE, // + true) + } catch (e: CertificateEncodingException) { + Timber.tag("AuthicateCloudPrester").e(e) + throw FatalBackendException(e) + } + } + + fun onAcceptWebDavCertificateDenied() { + finish() + } + + private inner class LocalStorageAuthStrategy : AuthStrategy { + private var authenticationStarted = false + override fun supports(cloud: CloudModel): Boolean { + return cloud.cloudType() == CloudTypeModel.LOCAL + } + + override fun resumed(intent: AuthenticateCloudIntent) { + if (!authenticationStarted) { + startAuthentication(intent.cloud()) + } + } + + private fun startAuthentication(cloud: CloudModel) { + authenticationStarted = true + requestPermissions(PermissionsResultCallbacks.onLocalStorageAuthenticated(cloud), // + R.string.permission_snackbar_auth_local_vault, // + Manifest.permission.READ_EXTERNAL_STORAGE, // + Manifest.permission.WRITE_EXTERNAL_STORAGE) + } + } + + @Callback + fun onLocalStorageAuthenticated(result: PermissionsResult, cloud: CloudModel) { + if (result.granted()) { + succeedAuthenticationWith(cloud.toCloud()) + } else { + failAuthentication(PermissionNotGrantedException(R.string.permission_snackbar_auth_local_vault)) + } + } + + private fun encrypt(password: String): String { + return CredentialCryptor // + .getInstance(context()) // + .encrypt(password) + } + + private inner class FailingAuthStrategy : AuthStrategy { + override fun supports(cloud: CloudModel): Boolean { + return false + } + + override fun resumed(intent: AuthenticateCloudIntent) { + view?.showError(R.string.error_authentication_failed) + finish() + } + } + + private interface AuthStrategy { + fun supports(cloud: CloudModel): Boolean + fun resumed(intent: AuthenticateCloudIntent) + } + + companion object { + const val WEBDAV_ACCEPTED_UNTRUSTED_CERTIFICATE = "acceptedUntrustedCertificate" + } + + init { + unsubscribeOnDestroy(addOrChangeCloudConnectionUseCase, getUsernameUseCase) + } +} diff --git a/presentation/src/main/AndroidManifest.xml b/presentation/src/main/AndroidManifest.xml index 1e0c1af0..882a5e27 100644 --- a/presentation/src/main/AndroidManifest.xml +++ b/presentation/src/main/AndroidManifest.xml @@ -28,9 +28,10 @@ android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" - android:supportsRtl="true" android:requestLegacyExternalStorage="true" - android:theme="@style/AppTheme"> + android:supportsRtl="true" + android:theme="@style/AppTheme" + android:usesCleartextTraffic="true"> @@ -87,7 +88,7 @@ android:configChanges="orientation|keyboard" android:launchMode="singleTask"> - + @@ -101,19 +102,17 @@ - - - - - - + + + + + - @@ -121,15 +120,26 @@ - + + android:host="*" + android:scheme="cryptomator" /> + + + + + + + + diff --git a/presentation/src/main/java/org/cryptomator/presentation/CryptomatorApp.kt b/presentation/src/main/java/org/cryptomator/presentation/CryptomatorApp.kt index acd019cc..685dbc73 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/CryptomatorApp.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/CryptomatorApp.kt @@ -42,8 +42,14 @@ class CryptomatorApp : MultiDexApplication(), HasComponent override fun onCreate() { super.onCreate() setupLogging() - - val flavor = if (BuildConfig.FLAVOR == "license") "License Edition" else "Google Play Edition" + val flavor = when (BuildConfig.FLAVOR) { + "apkstore" -> { + "APK Store Edition" + } + "fdroid" -> { + "F-Droid Edition" + } else -> "Google Play Edition" + } Timber.tag("App").i("Cryptomator v%s (%d) \"%s\" started on android %s / API%d using a %s", // BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, flavor, // Build.VERSION.RELEASE, Build.VERSION.SDK_INT, // diff --git a/presentation/src/main/java/org/cryptomator/presentation/e/c.java b/presentation/src/main/java/org/cryptomator/presentation/e/c.java new file mode 100644 index 00000000..8cba6ec2 --- /dev/null +++ b/presentation/src/main/java/org/cryptomator/presentation/e/c.java @@ -0,0 +1,57 @@ +package org.cryptomator.presentation.e; + +import java.io.Serializable; +import java.util.Set; + +/** + * This file is the obfuscated AutoUploadFilesStore of Cryptomator in version 1.5.10 + * and is used to recover it in version 1.5.11 and 1.5.11-beta2 + * + * TODO Delete as soon as possible + * + * See more information: https://github.com/cryptomator/android/issues/250 + */ + +public final class c implements Serializable { + + public static final a Qb = new a(); + private static final long serialVersionUID = -2190476748996271234L; + + private final Set vlb; + + public c(Set paramSet) { + this.vlb = paramSet; + } + + public boolean equals(Object paramObject) { + if (this != paramObject) { + if (paramObject instanceof c) { + Object paramObject2 = ((c)paramObject).vlb; + return (this.vlb == null) ? ((paramObject2 == null)) : this.vlb.equals(paramObject2); + } + return false; + } + return true; + } + + public int hashCode() { + Set set = this.vlb; + return (set != null) ? set.hashCode() : 0; + } + + public final Set mE() { + return this.vlb; + } + + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("AutoUploadFilesStore(uris="); + stringBuilder.append(this.vlb); + stringBuilder.append(")"); + return stringBuilder.toString(); + } + + public static final class a { + private a() {} + } +} diff --git a/presentation/src/main/java/org/cryptomator/presentation/i/a.java b/presentation/src/main/java/org/cryptomator/presentation/i/a.java new file mode 100644 index 00000000..9444f86d --- /dev/null +++ b/presentation/src/main/java/org/cryptomator/presentation/i/a.java @@ -0,0 +1,57 @@ +package org.cryptomator.presentation.i; + +import java.io.Serializable; +import java.util.Set; + +/** + * This file is the obfuscated AutoUploadFilesStore of Cryptomator in version 1.5.11-beta1 + * and is used to recover it in version 1.5.11-beta2 + * + * TODO Delete as soon as possible + * + * See more information: https://github.com/cryptomator/android/issues/250 + */ + +public final class a implements Serializable { + + private static final long serialVersionUID = 5147365921479820025L; + private final Set b; + + public a(Set paramSet) { + this.b = paramSet; + } + + public final Set b() { + return this.b; + } + + public boolean equals(Object paramObject) { + if (this != paramObject) { + if (paramObject instanceof a) { + Object paramObject2 = ((a)paramObject).b; + return (this.b == null) ? ((paramObject2 == null)) : this.b.equals(paramObject2); + } + return false; + } + return true; + } + + public int hashCode() { + int bool; + Set set = this.b; + if (set != null) { + bool = set.hashCode(); + } else { + bool = 0; + } + return bool; + } + + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("AutoUploadFilesStore(uris="); + stringBuilder.append(this.b); + stringBuilder.append(")"); + return stringBuilder.toString(); + } +} diff --git a/presentation/src/main/java/org/cryptomator/presentation/presenter/ChooseCloudServicePresenter.kt b/presentation/src/main/java/org/cryptomator/presentation/presenter/ChooseCloudServicePresenter.kt index afabda80..9091c8a6 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/presenter/ChooseCloudServicePresenter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/presenter/ChooseCloudServicePresenter.kt @@ -5,6 +5,7 @@ import org.cryptomator.domain.di.PerView import org.cryptomator.domain.exception.FatalBackendException import org.cryptomator.domain.usecases.cloud.GetCloudsUseCase import org.cryptomator.generator.Callback +import org.cryptomator.presentation.BuildConfig import org.cryptomator.presentation.R import org.cryptomator.presentation.exception.ExceptionHandlers import org.cryptomator.presentation.intent.Intents @@ -32,6 +33,11 @@ class ChooseCloudServicePresenter @Inject constructor( // override fun resumed() { val cloudTypeModels: MutableList = ArrayList(listOf(*CloudTypeModel.values())) cloudTypeModels.remove(CloudTypeModel.CRYPTO) + + if(BuildConfig.FLAVOR == "fdroid") { + cloudTypeModels.remove(CloudTypeModel.GOOGLE_DRIVE) + } + view?.render(cloudTypeModels) } diff --git a/presentation/src/main/java/org/cryptomator/presentation/presenter/CloudSettingsPresenter.kt b/presentation/src/main/java/org/cryptomator/presentation/presenter/CloudSettingsPresenter.kt index 4b2b6f99..c8893477 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/presenter/CloudSettingsPresenter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/presenter/CloudSettingsPresenter.kt @@ -9,6 +9,7 @@ import org.cryptomator.domain.usecases.cloud.GetAllCloudsUseCase import org.cryptomator.domain.usecases.cloud.GetCloudsUseCase import org.cryptomator.domain.usecases.cloud.LogoutCloudUseCase import org.cryptomator.generator.Callback +import org.cryptomator.presentation.BuildConfig import org.cryptomator.presentation.R import org.cryptomator.presentation.exception.ExceptionHandlers import org.cryptomator.presentation.intent.Intents @@ -114,7 +115,10 @@ class CloudSettingsPresenter @Inject constructor( // private inner class CloudsSubscriber : DefaultResultHandler>() { override fun onSuccess(clouds: List) { - val cloudModel = cloudModelMapper.toModels(clouds).filter { isSingleLoginCloud(it) }.toMutableList() // + val cloudModel = cloudModelMapper.toModels(clouds) // + .filter { isSingleLoginCloud(it) } // + .filter { cloud -> !(BuildConfig.FLAVOR == "fdroid" && cloud.cloudType() == CloudTypeModel.GOOGLE_DRIVE)} // + .toMutableList() // .also { it.add(aWebdavCloud()) it.add(aLocalCloud()) diff --git a/presentation/src/main/java/org/cryptomator/presentation/presenter/LicenseCheckPresenter.kt b/presentation/src/main/java/org/cryptomator/presentation/presenter/LicenseCheckPresenter.kt index 8a321d0f..278a6dfb 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/presenter/LicenseCheckPresenter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/presenter/LicenseCheckPresenter.kt @@ -16,8 +16,8 @@ class LicenseCheckPresenter @Inject internal constructor( private val sharedPreferencesHandler: SharedPreferencesHandler) : Presenter(exceptionHandlers) { fun validate(data: Uri?) { - if (data != null) { - val license = data.lastPathSegment ?: "" + data?.let { + val license = it.fragment ?: it.lastPathSegment ?: "" view?.showOrUpdateLicenseDialog(license) doLicenseCheckUsecase .withLicense(license) diff --git a/presentation/src/main/java/org/cryptomator/presentation/presenter/SettingsPresenter.kt b/presentation/src/main/java/org/cryptomator/presentation/presenter/SettingsPresenter.kt index be850874..18e824ef 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/presenter/SettingsPresenter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/presenter/SettingsPresenter.kt @@ -66,9 +66,13 @@ class SettingsPresenter @Inject internal constructor( } private fun errorReportEmailBody(): String { - var variant = "PlayStore" - if (BuildConfig.FLAVOR == "license") { - variant = "ApkStore" + val variant = when (BuildConfig.FLAVOR) { + "apkstore" -> { + "APK Store" + } + "fdroid" -> { + "F-Droid" + } else -> "Google Play" } return StringBuilder().append("## ").append(context().getString(R.string.error_report_subject)).append("\n\n") // .append("### ").append(context().getString(R.string.error_report_section_summary)).append('\n') // diff --git a/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt b/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt index 4e85e0aa..74a3d225 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt @@ -105,12 +105,12 @@ class VaultListPresenter @Inject constructor( // } private fun checkLicense() { - if (BuildConfig.FLAVOR == "license") { + if (BuildConfig.FLAVOR == "apkstore" || BuildConfig.FLAVOR == "fdroid") { licenseCheckUseCase // .withLicense("") // .run(object : NoOpResultHandler() { override fun onSuccess(licenseCheck: LicenseCheck) { - if (sharedPreferencesHandler.doUpdate()) { + if (BuildConfig.FLAVOR == "apkstore" && sharedPreferencesHandler.doUpdate()) { checkForAppUpdates() } } diff --git a/presentation/src/main/java/org/cryptomator/presentation/service/PhotoContentJob.kt b/presentation/src/main/java/org/cryptomator/presentation/service/PhotoContentJob.kt index 8250f256..68ee0e5a 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/service/PhotoContentJob.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/service/PhotoContentJob.kt @@ -15,7 +15,9 @@ import android.provider.MediaStore import android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI import androidx.annotation.RequiresApi import org.cryptomator.domain.exception.FatalBackendException +import org.cryptomator.presentation.R import org.cryptomator.presentation.util.FileUtil +import org.cryptomator.presentation.util.ResourceHelper import org.cryptomator.util.file.MimeTypeMap_Factory import org.cryptomator.util.file.MimeTypes import timber.log.Timber @@ -121,7 +123,7 @@ class PhotoContentJob : JobService() { private const val PHOTOS_CONTENT_JOB = 23 init { - val builder = JobInfo.Builder(PHOTOS_CONTENT_JOB, ComponentName("org.cryptomator", PhotoContentJob::class.java.name)) + val builder = JobInfo.Builder(PHOTOS_CONTENT_JOB, ComponentName(ResourceHelper.getString(R.string.app_id), PhotoContentJob::class.java.name)) builder.addTriggerContentUri(JobInfo.TriggerContentUri(EXTERNAL_CONTENT_URI, FLAG_NOTIFY_FOR_DESCENDANTS)) builder.addTriggerContentUri(JobInfo.TriggerContentUri(MEDIA_URI, FLAG_NOTIFY_FOR_DESCENDANTS)) jobInfo = builder.build() diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/CloudSettingsActivity.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/CloudSettingsActivity.kt index 51ee01c5..311966a2 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/CloudSettingsActivity.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/CloudSettingsActivity.kt @@ -21,7 +21,7 @@ class CloudSettingsActivity : BaseActivity(), CloudSettingsView { setSupportActionBar(toolbar) } - override fun createFragment(): Fragment? = CloudSettingsFragment() + override fun createFragment(): Fragment = CloudSettingsFragment() override fun render(cloudModels: List) { cloudSettingsFragment().showClouds(cloudModels) diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/LicensesFragment.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/LicensesFragment.kt index e9be9f18..72250c0f 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/LicensesFragment.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/LicensesFragment.kt @@ -1,11 +1,10 @@ package org.cryptomator.presentation.ui.fragment import android.os.Bundle -import androidx.preference.PreferenceFragment - +import androidx.preference.PreferenceFragmentCompat import org.cryptomator.presentation.R -class LicensesFragment : PreferenceFragment() { +class LicensesFragment : PreferenceFragmentCompat() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { addPreferencesFromResource(R.xml.licenses) } diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/SettingsFragment.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/SettingsFragment.kt index 08694de5..f27a3af0 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/SettingsFragment.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/SettingsFragment.kt @@ -148,18 +148,28 @@ class SettingsFragment : PreferenceFragmentCompat() { } private fun setupLicense() { - if (BuildConfig.FLAVOR == "license") { - findPreference(SharedPreferencesHandler.MAIL)?.title = format(getString(R.string.screen_settings_license_mail), sharedPreferencesHandler.mail()) - setupUpdateCheck() - } else { - preferenceScreen.removePreference(findPreference(LICENSE_ITEM_KEY)) - - val versionCategory = findPreference("versionCategory") as PreferenceCategory? - versionCategory?.removePreference(findPreference(UPDATE_CHECK_ITEM_KEY)) - versionCategory?.removePreference(findPreference(UPDATE_INTERVAL_ITEM_KEY)) + when (BuildConfig.FLAVOR) { + "apkstore" -> { + findPreference(SharedPreferencesHandler.MAIL)?.title = format(getString(R.string.screen_settings_license_mail), sharedPreferencesHandler.mail()) + setupUpdateCheck() + } + "fdroid" -> { + findPreference(SharedPreferencesHandler.MAIL)?.title = format(getString(R.string.screen_settings_license_mail), sharedPreferencesHandler.mail()) + removeUpdateCheck() + } + else -> { + preferenceScreen.removePreference(findPreference(LICENSE_ITEM_KEY)) + removeUpdateCheck() + } } } + private fun removeUpdateCheck() { + val versionCategory = findPreference("versionCategory") as PreferenceCategory? + versionCategory?.removePreference(findPreference(UPDATE_CHECK_ITEM_KEY)) + versionCategory?.removePreference(findPreference(UPDATE_INTERVAL_ITEM_KEY)) + } + fun setupUpdateCheck() { val preference = findPreference(UPDATE_CHECK_ITEM_KEY) @@ -195,7 +205,7 @@ class SettingsFragment : PreferenceFragmentCompat() { findPreference(SharedPreferencesHandler.PHOTO_UPLOAD)?.onPreferenceChangeListener = useAutoPhotoUploadChangedListener findPreference(SharedPreferencesHandler.USE_LRU_CACHE)?.onPreferenceChangeListener = useLruChangedListener findPreference(SharedPreferencesHandler.LRU_CACHE_SIZE)?.onPreferenceChangeListener = useLruChangedListener - if (BuildConfig.FLAVOR == "license") { + if (BuildConfig.FLAVOR == "apkstore") { findPreference(UPDATE_CHECK_ITEM_KEY)?.onPreferenceClickListener = updateCheckClickListener } } diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/layout/VaultListCoordinatorLayout.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/layout/VaultListCoordinatorLayout.kt index 1664b382..ffa345b7 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/layout/VaultListCoordinatorLayout.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/layout/VaultListCoordinatorLayout.kt @@ -2,7 +2,6 @@ package org.cryptomator.presentation.ui.layout import android.content.Context import android.graphics.Canvas -import android.graphics.Color import android.graphics.Paint import android.graphics.RectF import android.util.AttributeSet @@ -10,6 +9,7 @@ import android.util.DisplayMetrics import android.view.View import androidx.coordinatorlayout.widget.CoordinatorLayout import org.cryptomator.presentation.R +import timber.log.Timber import kotlin.math.cos import kotlin.math.sin @@ -44,18 +44,32 @@ class VaultListCoordinatorLayout : CoordinatorLayout { val floatingActionButton = findViewById(R.id.fab_vault) val centerXOfHint = (vaultCreationHint.left + vaultCreationHint.right) / 2f val bottomOfHint = vaultCreationHint.bottom.toFloat() - val leftOfFloatingActionButton = floatingActionButton.left.toFloat() val topOfFloatingActionButton = floatingActionButton.top.toFloat() - arcFrom(centerXOfHint + dpToPixels(10f), bottomOfHint + dpToPixels(5f)) // - .to(leftOfFloatingActionButton - dpToPixels(3f), topOfFloatingActionButton + dpToPixels(5f)) // - .spanningAnAngleOf(60.0f) // - .build() // - .draw(canvas, strokeBlackWithWidthOf1f()) + + when (val layoutDirection = resources.configuration.layoutDirection) { + View.LAYOUT_DIRECTION_LTR -> { + arcFrom(centerXOfHint + dpToPixels(10f), bottomOfHint + dpToPixels(5f), layoutDirection) // + .to(floatingActionButton.left.toFloat() - dpToPixels(3f), topOfFloatingActionButton + dpToPixels(5f)) // + .spanningAnAngleOf(60.0f) // + .build() // + .draw(canvas, strokeLineWithWidthOf1f()) + } + View.LAYOUT_DIRECTION_RTL -> { + arcFrom(floatingActionButton.right.toFloat() - dpToPixels(3f), bottomOfHint + dpToPixels(5f), layoutDirection) // + .to(centerXOfHint + dpToPixels(10f), topOfFloatingActionButton + dpToPixels(5f)) // + .spanningAnAngleOf(60.0f) // + .build() // + .draw(canvas, strokeLineWithWidthOf1f()) + } + else -> { + Timber.tag("VaultListCoordinatorLay").e("Layout direction not supported, skip drawing arc") + } + } } - private fun strokeBlackWithWidthOf1f(): Paint { + private fun strokeLineWithWidthOf1f(): Paint { val paint = Paint() - paint.color = Color.BLACK + paint.color = context.getColor(R.color.textColorPrimary) paint.strokeWidth = dpToPixels(1f) paint.isAntiAlias = true paint.style = Paint.Style.STROKE @@ -66,7 +80,7 @@ class VaultListCoordinatorLayout : CoordinatorLayout { return dp * pixelsPerDp } - private class ArcBuilder(val x1: Float, val y1: Float) { + private class ArcBuilder(val x1: Float, val y1: Float, val layoutDirection: Int) { var angle = 0f var x2 = 0f var y2 = 0f @@ -95,6 +109,7 @@ class VaultListCoordinatorLayout : CoordinatorLayout { private val bottom: Float private val start: Float private val angle: Float = b.angle + private val layoutDirection: Int = b.layoutDirection fun draw(canvas: Canvas, paint: Paint) { val rect = RectF() @@ -107,23 +122,51 @@ class VaultListCoordinatorLayout : CoordinatorLayout { } init { - start = 180f - angle val sin = sin(TWO_PI * angle / 360).toFloat() val cos = cos(TWO_PI * angle / 360).toFloat() val widthCorrection = 1f / cos val heightCorrection = 1f / sin val w = (b.x2 - b.x1) * 2 * widthCorrection val h = (b.y2 - b.y1) * 2 * heightCorrection - left = b.x1 - right = b.x1 + w + + start = when (layoutDirection) { + View.LAYOUT_DIRECTION_LTR -> { + 180f - angle + } + View.LAYOUT_DIRECTION_RTL -> { + 0f + } + else -> throw IllegalStateException("Not supported layout direction") + } + + left = when (layoutDirection) { + View.LAYOUT_DIRECTION_LTR -> { + b.x1 + } + View.LAYOUT_DIRECTION_RTL -> { + b.x2 - w + } + else -> throw IllegalStateException("Not supported layout direction") + } + + right = when (layoutDirection) { + View.LAYOUT_DIRECTION_LTR -> { + b.x1 + w + } + View.LAYOUT_DIRECTION_RTL -> { + b.x2 + } + else -> throw IllegalStateException("Not supported layout direction") + } + top = b.y1 - h / 2 bottom = b.y1 + h / 2 } } companion object { - private fun arcFrom(x1: Float, y1: Float): ArcBuilder { - return ArcBuilder(x1, y1) + private fun arcFrom(x1: Float, y1: Float, layoutDirection: Int): ArcBuilder { + return ArcBuilder(x1, y1, layoutDirection) } } } diff --git a/presentation/src/main/java/org/cryptomator/presentation/util/FileUtil.kt b/presentation/src/main/java/org/cryptomator/presentation/util/FileUtil.kt index 8996966a..a0a24cfa 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/util/FileUtil.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/util/FileUtil.kt @@ -17,10 +17,9 @@ import java.io.* import java.util.* import javax.inject.Inject -class FileUtil @Inject constructor(private val context: Context, mimeTypes: MimeTypes) { +class FileUtil @Inject constructor(private val context: Context, private val mimeTypes: MimeTypes) { private var decryptedFileStorage: File = File(context.cacheDir, "decrypted") - private val mimeTypes: MimeTypes = mimeTypes fun cleanup() { cleanupDir(context.cacheDir) @@ -126,7 +125,9 @@ class FileUtil @Inject constructor(private val context: Context, mimeTypes: Mime fun getImagePreviewFiles(path: String): ImagePreviewFilesStore { try { - ObjectInputStream(FileInputStream(path)).use { objectInputStream -> return objectInputStream.readObject() as ImagePreviewFilesStore } + ObjectInputStream(FileInputStream(path)).use { objectInputStream -> + return objectInputStream.readObject() as ImagePreviewFilesStore + } } catch (e: ClassNotFoundException) { Timber // .tag("FileUtil") // @@ -140,40 +141,39 @@ class FileUtil @Inject constructor(private val context: Context, mimeTypes: Mime } } - fun addImageToAutoUploads(path: String) { - val file = File(decryptedFileStorage, AUTO_UPLOAD_IMAGE__FILE_NAMES) - val paths = getAutoUploadFilesStore(file).uris + path - addImageToAutoUploads(paths) + fun addImageToAutoUploads(path: String): AutoUploadFilesStore { + val paths = getAutoUploadFilesStore().uris + path + return addImageToAutoUploads(paths) } - private fun addImageToAutoUploads(paths: Set) { - addImageToAutoUploads(AutoUploadFilesStore(paths)) + private fun addImageToAutoUploads(paths: Set): AutoUploadFilesStore { + return addImageToAutoUploads(AutoUploadFilesStore(paths)) } @Synchronized - private fun addImageToAutoUploads(autoUploadFilesStore: AutoUploadFilesStore) { + private fun addImageToAutoUploads(autoUploadFilesStore: AutoUploadFilesStore): AutoUploadFilesStore { try { decryptedFileStorage.mkdir() + val file = File(decryptedFileStorage, AUTO_UPLOAD_IMAGE__FILE_NAMES) - val out: ObjectOutput = ObjectOutputStream(FileOutputStream(file.path)) - out.writeObject(autoUploadFilesStore) - out.close() + + ObjectOutputStream(FileOutputStream(file.path)).use { objectOutputStream -> + objectOutputStream.writeObject(autoUploadFilesStore) + objectOutputStream.close() + } + + return autoUploadFilesStore } catch (e: IOException) { Timber // .tag("FileUtil") // .e(e, "Failed to store image preview file list for PreviewActivity") + throw FatalBackendException(e) } } - @get:Throws(FatalBackendException::class) - val autoUploadFilesStore: AutoUploadFilesStore - get() { - val file = File(decryptedFileStorage, AUTO_UPLOAD_IMAGE__FILE_NAMES) - return getAutoUploadFilesStore(file) - } - @Synchronized - private fun getAutoUploadFilesStore(file: File): AutoUploadFilesStore { + fun getAutoUploadFilesStore(): AutoUploadFilesStore { + val file = File(decryptedFileStorage, AUTO_UPLOAD_IMAGE__FILE_NAMES) if (!file.exists()) { return AutoUploadFilesStore(HashSet()) } @@ -184,20 +184,9 @@ class FileUtil @Inject constructor(private val context: Context, mimeTypes: Mime return autoUploadFilesStore } } catch (e: InvalidClassException) { - Timber // - .tag("FileUtil") // - .e(e, "This is a bug in Cryptomator version 1.4.1, only fix is to delete the AutoUploadFilesStore but no image inside so no problem") - if (!file.delete()) { - Timber // - .tag("FileUtil") // - .e("Failed to delete AutoUploadFilesStore") - } - throw FatalBackendException(e) - } catch (e: ClassNotFoundException) { - Timber // - .tag("FileUtil") // - .e(e, "Failed to read image preview file from list for PreviewActivity") - throw FatalBackendException(e) + return tryRecoverAutoUploadFilesStoreDueToFileObfuscation(file) + } catch (e: ClassCastException) { + return tryRecoverAutoUploadFilesStoreDueToFileObfuscation(file) } catch (e: IOException) { Timber .tag("FileUtil") @@ -206,20 +195,47 @@ class FileUtil @Inject constructor(private val context: Context, mimeTypes: Mime } } + /** + * This method tries to recover the AutoUploadFilesStore which was obfuscated in version 1.5.10 and 1.5.11-beta1, each differently + */ + private fun tryRecoverAutoUploadFilesStoreDueToFileObfuscation(file: File): AutoUploadFilesStore { + Timber.tag("FileUtil").i("Try to recover AutoUploadFilesStore using class c or a") + try { + ObjectInputStream(FileInputStream(file)).use { objectInputStream -> + val uploadPaths = when (val obj = objectInputStream.readObject()) { + is org.cryptomator.presentation.e.c -> obj.mE() // version 1.5.10 + is org.cryptomator.presentation.i.a -> obj.b() // version 1.5.11-beta1 + else -> null + } + when { + uploadPaths != null -> { + Timber.tag("FileUtil").i("Nailed it! Successfully recovered AutoUploadFilesStore!") + file.delete() + return AutoUploadFilesStore(uploadPaths) + } + else -> throw FatalBackendException("Failed to recover AutoUploadFilesStore") + } + } + } catch (e: Exception) { + throw FatalBackendException("Failed to recover AutoUploadFilesStore", e) + } + } + @Synchronized - fun removeImagesFromAutoUploads(names: Set) { - val autoUploadFilesStore = autoUploadFilesStore + fun removeImagesFromAutoUploads(names: Set): AutoUploadFilesStore { + val autoUploadFilesStore = getAutoUploadFilesStore() var paths = autoUploadFilesStore.uris if (autoUploadFilesStore.uris.isEmpty()) { - return + return autoUploadFilesStore } val dirPath = File(autoUploadFilesStore.uris.iterator().next()).parent names.forEach { name -> paths = paths.minus(String.format("%s/%s", dirPath, name)) } - addImageToAutoUploads(paths) + + return addImageToAutoUploads(paths) } class FileInfo(val name: String, mimeTypes: MimeTypes) { diff --git a/presentation/src/main/res/layout/activity_empty_dir_file_info.xml b/presentation/src/main/res/layout/activity_empty_dir_file_info.xml index 33c9c3a1..d7fb3ca0 100644 --- a/presentation/src/main/res/layout/activity_empty_dir_file_info.xml +++ b/presentation/src/main/res/layout/activity_empty_dir_file_info.xml @@ -11,6 +11,7 @@ android:layout_height="wrap_content" /> diff --git a/presentation/src/main/res/layout/dialog_biometric_auth_key_invalidated.xml b/presentation/src/main/res/layout/dialog_biometric_auth_key_invalidated.xml index 8b55cc52..6b765109 100644 --- a/presentation/src/main/res/layout/dialog_biometric_auth_key_invalidated.xml +++ b/presentation/src/main/res/layout/dialog_biometric_auth_key_invalidated.xml @@ -4,8 +4,8 @@ android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" - android:paddingLeft="@dimen/activity_horizontal_margin" - android:paddingRight="@dimen/activity_horizontal_margin" + android:paddingStart="@dimen/activity_horizontal_margin" + android:paddingEnd="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin"> diff --git a/presentation/src/main/res/layout/dialog_bottom_sheet_vault_action.xml b/presentation/src/main/res/layout/dialog_bottom_sheet_vault_action.xml index 488d687c..89e44ff0 100644 --- a/presentation/src/main/res/layout/dialog_bottom_sheet_vault_action.xml +++ b/presentation/src/main/res/layout/dialog_bottom_sheet_vault_action.xml @@ -18,8 +18,6 @@ android:ellipsize="middle" android:gravity="center_vertical" android:paddingEnd="16dp" - android:paddingLeft="16dp" - android:paddingRight="16dp" android:paddingStart="16dp" android:singleLine="true" android:textSize="16sp" diff --git a/presentation/src/main/res/layout/dialog_bottom_sheet_vault_settings.xml b/presentation/src/main/res/layout/dialog_bottom_sheet_vault_settings.xml index 51e5360b..442d76b2 100644 --- a/presentation/src/main/res/layout/dialog_bottom_sheet_vault_settings.xml +++ b/presentation/src/main/res/layout/dialog_bottom_sheet_vault_settings.xml @@ -22,8 +22,6 @@ android:layout_width="@dimen/thumbnail_size" android:layout_height="@dimen/thumbnail_size" android:layout_marginEnd="16dp" - android:layout_marginLeft="16dp" - android:layout_marginRight="16dp" android:layout_marginStart="16dp" /> diff --git a/presentation/src/main/res/layout/dialog_no_screen_lock_set.xml b/presentation/src/main/res/layout/dialog_no_screen_lock_set.xml index 45aaa0c7..7ab9fee8 100644 --- a/presentation/src/main/res/layout/dialog_no_screen_lock_set.xml +++ b/presentation/src/main/res/layout/dialog_no_screen_lock_set.xml @@ -22,8 +22,6 @@ android:layout_marginTop="27dp" android:checked="true" android:paddingEnd="16dp" - android:paddingLeft="16dp" - android:paddingRight="16dp" android:paddingStart="16dp" android:text="@string/dialog_no_screen_lock_checkbox" /> diff --git a/presentation/src/main/res/layout/dialog_upload_loading.xml b/presentation/src/main/res/layout/dialog_upload_loading.xml index 94be5025..79cd0eda 100644 --- a/presentation/src/main/res/layout/dialog_upload_loading.xml +++ b/presentation/src/main/res/layout/dialog_upload_loading.xml @@ -12,8 +12,8 @@ android:id="@+id/file_upload" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingLeft="16dp" - android:paddingRight="16dp" + android:paddingStart="16dp" + android:paddingEnd="16dp" android:paddingBottom="8dp" android:textSize="20sp" /> diff --git a/presentation/src/main/res/layout/dialog_vault_delete_confirmation.xml b/presentation/src/main/res/layout/dialog_vault_delete_confirmation.xml index e8c44be2..66c2889a 100644 --- a/presentation/src/main/res/layout/dialog_vault_delete_confirmation.xml +++ b/presentation/src/main/res/layout/dialog_vault_delete_confirmation.xml @@ -8,8 +8,8 @@ android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" - android:paddingLeft="@dimen/activity_horizontal_margin" - android:paddingRight="@dimen/activity_horizontal_margin" + android:paddingStart="@dimen/activity_horizontal_margin" + android:paddingEnd="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin"> @@ -30,8 +28,6 @@ android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginEnd="16dp" - android:layout_marginLeft="16dp" - android:layout_marginRight="16dp" android:layout_marginStart="16dp" android:layout_marginTop="16dp" android:layout_toEndOf="@id/cloudNodeImage" diff --git a/presentation/src/main/res/layout/item_cloud_setting.xml b/presentation/src/main/res/layout/item_cloud_setting.xml index 8011b74c..6a26fddb 100644 --- a/presentation/src/main/res/layout/item_cloud_setting.xml +++ b/presentation/src/main/res/layout/item_cloud_setting.xml @@ -16,8 +16,6 @@ android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginEnd="16dp" - android:layout_marginLeft="16dp" - android:layout_marginRight="16dp" android:layout_marginStart="16dp" android:layout_toEndOf="@+id/cloudImage" android:orientation="vertical"> diff --git a/presentation/src/main/res/layout/item_shared_files.xml b/presentation/src/main/res/layout/item_shared_files.xml index 2c8c6763..8632a73c 100644 --- a/presentation/src/main/res/layout/item_shared_files.xml +++ b/presentation/src/main/res/layout/item_shared_files.xml @@ -17,8 +17,6 @@ android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginEnd="16dp" - android:layout_marginLeft="16dp" - android:layout_marginRight="16dp" android:layout_marginStart="16dp" android:layout_toEndOf="@+id/fileImage" android:ellipsize="middle" diff --git a/presentation/src/main/res/layout/item_vault.xml b/presentation/src/main/res/layout/item_vault.xml index 5ce193a6..5d5a861f 100644 --- a/presentation/src/main/res/layout/item_vault.xml +++ b/presentation/src/main/res/layout/item_vault.xml @@ -17,8 +17,6 @@ android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginEnd="16dp" - android:layout_marginLeft="16dp" - android:layout_marginRight="16dp" android:layout_marginStart="16dp" android:layout_toEndOf="@+id/cloudImage" android:layout_toStartOf="@+id/unlockedImage" @@ -52,8 +50,8 @@ android:layout_toStartOf="@+id/settings" android:background="?android:attr/selectableItemBackground" android:paddingBottom="10dp" - android:paddingLeft="14dp" - android:paddingRight="14dp" + android:paddingStart="14dp" + android:paddingEnd="14dp" android:paddingTop="10dp" android:src="@drawable/vault_unlocked" app:tint="@color/colorPrimary" diff --git a/presentation/src/main/res/layout/view_default_local_cloud.xml b/presentation/src/main/res/layout/view_default_local_cloud.xml index b6e693e6..21250ce5 100644 --- a/presentation/src/main/res/layout/view_default_local_cloud.xml +++ b/presentation/src/main/res/layout/view_default_local_cloud.xml @@ -19,8 +19,6 @@ android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginEnd="16dp" - android:layout_marginLeft="16dp" - android:layout_marginRight="16dp" android:layout_marginStart="16dp" android:layout_marginTop="16dp" android:layout_toEndOf="@id/iv_cloud_model_image" /> diff --git a/presentation/src/main/res/layout/view_dialog_error.xml b/presentation/src/main/res/layout/view_dialog_error.xml index 9f828d34..16a38167 100644 --- a/presentation/src/main/res/layout/view_dialog_error.xml +++ b/presentation/src/main/res/layout/view_dialog_error.xml @@ -5,8 +5,8 @@ android:layout_height="wrap_content" android:gravity="center" android:orientation="horizontal" - android:paddingLeft="16dp" - android:paddingRight="16dp" + android:paddingStart="16dp" + android:paddingEnd="16dp" android:visibility="gone"> diff --git a/presentation/src/main/res/values-de/strings.xml b/presentation/src/main/res/values-de/strings.xml index 4eb68f4a..6af46287 100644 --- a/presentation/src/main/res/values-de/strings.xml +++ b/presentation/src/main/res/values-de/strings.xml @@ -1,11 +1,7 @@ - - Cryptomator Verschlüsseln - @string/app_name - Ein Fehler ist aufgetreten Authentifizierung fehlgeschlagen @@ -29,134 +25,92 @@ Beim entschlüsseln des WebDAV-Passworts trat ein Fehler auf. Bitte in den Einstellungen erneut festlegen. Die Play Services sind nicht installiert Biometrischer Login abgebrochen - - - Crypto - Dropbox - Google Drive - OneDrive - WebDAV Lokaler Speicher - - Erlauben Sie Cryptomator Zugriff auf Ihren Speicher, um eine Datei zu exportieren Erlauben Sie Cryptomator Zugriff auf Ihren Speicher, um eine Datei hochzuladen Erlauben Sie Cryptomator Zugriff auf Ihren Speicher, um eine Datei zu teilen - Einstellungen Suche - Weiter Vorheriges - + Weiter Sortieren - A - Z - Z - A Neueste zuerst Älteste zuerst Größte zuerst Kleinste zuerst - - Zu Cryptomator hinzufügen Neuen Tresor anlegen Vorhandenen Tresor hinzufügen - @string/screen_file_browser_node_action_rename Entfernen Hier einen neuen Tresor erstellen Passwort wurde erfolgreich geändert - Tresor - Neuen Tresor anlegen Masterkey-Datei auswählen - @string/screen_vault_list_action_create_new_vault Hier ablegen Tresorname: %1$s - Verschieben - Verschieben von %1$s nach %2$d Elemente verschieben nach - + Verschieben Leerer Ordner - %1$s geändert vor %1$s - Teilen mit Wählen Sie einen Ablageort aus Auswählen Nichts zum teilen - Zu %1$s hinzufügen Ordner erstellen Text-Datei erstellen Dateien hochladen Dateien - Datei exportiert + Dateien exportiert Nichts zum exportieren Download-Verzeichnis konnte nicht erstellt werden - Teilen Umbenennen Bearbeiten - @string/screen_file_browser_move_button_text Exportieren Löschen Öffnen mit… - - Keine Verbindung - Wiederholen - Elemente auswählen %1$d ausgewählt Elemente auswählen Alle elemente auswählen Aktualisieren - - Dateien exportiert - + Keine Verbindung + Wiederholen Erfolgreich gespeichert - Speicher %1$s unter… - text Datei Dateien Dateinamen müssen eindeutig sein, bitte benennen Sie die Duplikate um. - @string/screen_share_files_content_files Speicherort Speichern Dateien verschlüsselt text.txt - Cloud-Dienst - @string/screen_vault_list_action_add_existing_vault - @string/screen_vault_list_action_create_new_vault - + Neuen Tresor anlegen Ort auswählen - @string/screen_file_browser_node_action_edit_text - @string/screen_vault_list_vault_action_delete Hier einen neuen Ort hinzufügen Server scheint nicht WebDAV-kompatibel zu sein Benutzerdefinierte Orte Standard-Speicher Weitere Orte sind nicht verfügbar. - - @string/cloud_names_webdav - URL Benutzername Passwort Verbinden @@ -164,31 +118,23 @@ URL ist ungültig. Benutzername muss ausgefüllt werden. Passwort muss ausgefüllt werden. - - @string/screen_vault_list_action_create_new_vault Tresorname muss ausgefüllt werden. Tresorname Erstellen - Passwort setzen Passwort muss ausgefüllt werden. Passwort stimmt nicht mit dem wiederholten Passwort überein. Fertig WICHTIG: Wenn Sie Ihr Passwort vergessen, gibt es keine Möglichkeit die Daten zu entschlüsseln. - @string/screen_webdav_settings_password_label Passwort wiederholen - Sehr Schwach Schwach Mittel Stark Sehr Stark - - @string/snack_bar_action_title_settings - Allgemein Cloud-Dienste Biometrischer Login @@ -196,95 +142,62 @@ Nach Entsperrung mittels dem Gesichts, bestätigen (falls verfügbar) App blockieren, wenn verdeckt Bildschirm-Sicherheit - Search + Suche Live-Suche Suche mit Glob-Muster - Automatisch sperren Sperren nach Bei deaktiviertem Bildschirm - Automatisches Photo-Hochladen Tresor auswählen für das Hochladen Aktivieren Nur mit WLAN hochladen - Bilder abspeichern in… - Uns folgen Cryptomator-Website Folgen Sie uns auf Twitter Liken Sie uns auf Facebook - https://cryptomator.org/de - https://twitter.com/Cryptomator - https://facebook.com/Cryptomator - Rechtliches Lizenzen Lizenztexte - - Support Hilfe anfordern - https://cryptomator.org/de/contact/ Debug-Modus Log-Datei senden Senden fehlgeschlagen Sicherheitshinweise - https://docs.cryptomator.org/en/1.5/security/best-practices/ - Version Halte Tresore geöffnet während dem Editieren einer Datei - + Erweiterte Eigenschaften + Vorbereitungen zum Entsperren im Hintergrund - @string/screen_settings_cloud_settings_label WebDAV-Verbindungen Lokale Speicherorte Einloggen in Abmelden von - - Erweiterte Eigenschaften - Vorbereitungen zum Entsperren im Hintergrund - - @string/screen_settings_licenses_label - - + %1$s-Authentifizierung fehlgeschlagen. - \'%1$s\' nicht erreichbar Cryptomator hat erkannt, dass dieser Ordner nicht erreichbar ist. Möglicherweise wurde dieser durch eine andere Anwendung gelöscht oder wurde durch eine fehlerhafte Synchronisation mit der Cloud verursacht.\n\nVersuchen Sie die Verzeichnisdatei über Ihren Cloud-Anbieter auf eine vorhergehende Version, die nicht leer ist, wiederherzustellen. Die betroffene Datei ist:\n%1$s\n\nFalls dies nicht funktioniert, könnten Sie Sanitizer verwenden, um Ihren Tresor auf Fehler zu überprüfen und möglicherweise Daten wiederherzustellen. Mehr über Sanitizer - - Abbrechen - - @string/screen_file_browser_action_create_folder - @string/screen_enter_vault_name_button_text - - @string/screen_webdav_settings_password_label Entsperren - - Altes Passwort Neues Passwort - @string/screen_set_password_retype_password_label Passwort ändern Altes Passwort muss ausgefüllt werden. Neues Passwort muss ausgefüllt werden. Neue Passwort stimmt nicht mit dem wiederholten Passwort überein. - Tresor %1$s nicht gefunden Der Tresor wurde umbenannt, verschoben oder gelöscht. Entfernen Sie diesen aus der Tresorliste und fügen Sie ihn erneut hinzu um fortzufahren. Tresor jetzt entfernen? Entfernen - Datei existiert bereits Ersetzen Eine Datei namens \'%1$s\' existiert bereits. - Existierende überspringen Alle ersetzen Existierende ersetzen @@ -294,49 +207,28 @@ %d Dateien existieren bereits. Sollen diese ersetzt werden? Datei ersetzen? Dateien ersetzen? - Teilen nicht möglich Sie haben keinen Tresor eingerichtet. Bitte legen Sie zuerst einen Tresor mit der Cryptomator-App an. - OK Tresor erstellen - %1$s kann nicht geöffnet werden - @string/screen_file_browser_node_action_export Bitte installieren Sie eine App, die diese Datei öffnen kann. Möchten Sie die Datei stattdessen auf dem Gerät speichern? - Tresor umbenennen - @string/screen_file_browser_node_action_rename - Ordner umbenennen Datei umbenennen - @string/screen_file_browser_node_action_rename - Sie haben ungespeicherte Änderungen Möchten Sie wirklich beenden, ohne zu speichern? Verwerfen @string/dialog_button_cancel - - @string/screen_file_browser_action_create_new_text_file - @string/screen_enter_vault_name_button_text - @string/dialog_button_cancel @string/screen_share_files_new_text_file - - @string/screen_file_browser_node_action_delete Sind Sie sicher, dass sie den Tresor entfernen wollen? Dieser Vorgang wird den Tresor nur aus dieser Liste entfernen und nicht tatsächlich löschen. - Lade hoch… - @string/dialog_button_cancel Datei %1$d von %2$d - Exportiere (%1$d/%2$d) - @string/dialog_button_cancel - Bitte warten… Erstelle Ordner… Erstelle Text-Datei… Authentifizierung… - Benenne um… Lösche… Entsperre Tresor… @@ -348,105 +240,63 @@ Entschlüssele… Verschiebe… Sperren - Ungültiges SSL-Zertifikat Das SSL-Zertifikat ist ungültig. Wollen Sie diesem trotzdem vertrauen? - Details Dies könnte ein Sicherheitsrisiko sein. Ich weiß was ich tue. - Die Verwendung von HTTP ist unsicher. Wir empfehlen stattdessen die Nutzung von HTTPS. Wenn Sie sich der Risiken bewusst sind, können Sie mit HTTP fortfahren. Zu HTTPS ändern HTTPS nutzen? - Kein Sperrbildschirm ist gesetzt. Um Ihre Passwörter sicher speichern zu können, setzen Sie bitte mit OK ein Muster oder ein Passwort. Sperrbildschirm setzen? Sperrbildschirm setzen - Kein Fingerabdruck/Gesicht im System Legen Sie mindestens einen Fingerabdruck/Gesicht im System an, um diesen Dienst nutzen zu können. - In diesem Modus könnten sensible Daten in eine Log-Datei auf diesem Gerät geschrieben werden (z.B. Dateinamen und Pfade). Ausgeschlossen davon sind u.a. Passwörter und Cookies.\n\nDenken Sie daran, den Debug-Modus so schnell wie möglich wieder zu deaktivieren. Achtung Aktivieren - @string/dialog_button_cancel - Dies ist eine Sicherheitsfunktion und verhindert, dass andere Apps Nutzer dazu bringen, Dinge zu tun, die sie nicht tun wollen.\n\nDurch die Deaktivierung bestätigen Sie, dass Sie sich der Risiken bewusst sind. Achtung Deaktivieren - @string/dialog_button_cancel - App wird verdeckt Eine App zeigt etwas über Cryptomator an (z.B. ein Blaulichtfilter oder eine Nachtmodus-App). Aus Sicherheitsgründen ist Cryptomator deaktiviert.\n\nWie Cryptomator aktiviert werden kann Schließen - Dies ist eine Sicherheitsfunktion und verhindert, dass andere Apps Nutzer dazu bringen, Dinge zu tun, die sie nicht tun wollen.\n\nDurch die Deaktivierung bestätigen Sie, dass Sie sich der Risiken bewusst sind. - Sind Sie sicher, dass sie den Cloud-Dienst entfernen wollen? Dieser Vorgang wird den Cloud-Dienst und desen zugehörigen Tresor löschen. - @string/screen_file_browser_node_action_delete - @string/dialog_button_cancel - - @string/screen_file_browser_node_action_delete - @string/dialog_button_cancel %1$d Elemente löschen? Sind Sie sicher, dass Sie diese Elemente löschen wollen? Sind Sie sicher, dass Sie diese Datei löschen wollen? Dieser Vorgang wird den gesamten Ordnerinhalt löschen. Sind Sie sicher, dass Sie diesen Ordner löschen wollen? - Biometrischer Login deaktiviert Da der Schlüssel nicht mehr zur Verfügung steht, wurde der Biometrischer Login deaktiviert. Zur Reaktivierung öffnen Sie die Cryptomator-Einstellungen. - @string/dialog_unable_to_share_positive_button - - Beta-Version - Das ist eine Beta-Version, die das Tresor-Format 7 unterstützt. Bitte nicht mit einem produktiv eingesetzten Tresor verwenden oder dafür sorgen, dass gute Sicherungen vorhanden sind. - APK-Store Lizenz Cryptomator wurde ohne Google Play Store installiert. Geben Sie eine gültige Lizenz ein, falls nicht bereits vorhanden, kann sie unter folgender URL erworben werden: https://cryptomator.org/android/ Die eingegebene Lizenz ist nicht gültig. Stellen Sie sicher, dass sie korrekt eingegeben wurde. Keine Lizenz vorhanden. Geben Sie eine gültige Lizenz ein. - @string/dialog_unable_to_share_positive_button Beenden - - Danke für die Eingabe Ihrer gültige Lizenz %1$s. Lizenzbestätigung - @string/dialog_unable_to_share_positive_button - + Danke für die Eingabe Ihrer gültige Lizenz %1$s. Neue Version verfügbar Cryptomator mit auf den aktuellen Stand aktualisieren. Mit OK wird die neueste Version heruntergeladen. Daraufhin werden Sie aufgefordert sie zu installieren. Jetzt aktualisieren Download-Seite öffnen Später Download in Ausführung - Lade die aktuelle Version von Cryptomator herunter - Dieser Ordner ist ein symbolischer Link Sie können nicht in diesen symbolischen Link navigieren Zurück - Verzeichniss kann nicht geladen werden Der Ordner \'%1$s\' in der Cloud hat keine Verzeichniss-Datei. Es könnte sein, dass der Ordner auf einem anderen Gerät erstellt wurde und noch nicht vollständig mit der Cloud synchronisiert ist. Bitte überprüfen, ob die folgende Datei in der Cloud existiert:\n%2$s - @string/dialog_sym_link_back_button - + Beta-Version + Das ist eine Beta-Version, die das Tresor-Format 7 unterstützt. Bitte nicht mit einem produktiv eingesetzten Tresor verwenden oder dafür sorgen, dass gute Sicherungen vorhanden sind. Cryptomator benötigt Zugriff auf den Speicher um lokale Tresore zu nutzen Cryptomator benötigt Zugriff auf den Speicher um den automatischen Foto-Upload zu nutzen - - Android Fehlerbericht - Zusammenfassung - Beschreiben Sie ausführlich, was sie in der App getan haben oder verweisen Sie auf ein existierendes Support-Ticket. - Geräteinfo - - Null kB Bytes - kB - MB - GB - TB - Sekunde Sekunden @@ -462,52 +312,38 @@ Monate Jahr Jahre - Biometrischer Login Tresor mittels Biometrie entsperren Tresor-Passwort verwenden - Automatischer Upload nicht möglich - Tresore entsperrt: %1$d Auto-Lock in %1$s Alle sperren - Hochladen abbrechen Automatisches Foto-Hochladen läuft Lade hoch %1d/%2d - - %1$d Bilder wurden in den Tresor hochgeladen Automatisches Foto-Hochladen beendet - + %1$d Bilder wurden in den Tresor hochgeladen Fehler beim automatischen Photo-Hochladen Generaller Fehler während dem Hochladen. Ausgewählter Ordner für das Photo-Hochladen existiert nicht mehr. In der Einstellungen neuen auswählen Tresor gesperrt während dem hochladen, zum weiteren Hochladen entsperren - - @string/dialog_button_cancel - Tresor bleibt entsperrt bis die Datei nicht mehr editiert wird Datei mit Schreibrechten geöffnet - + Tresor bleibt entsperrt bis die Datei nicht mehr editiert wird Neueste Version installiert - Zwischenspeicher - Zwischenspeicher leeren Zwischenspeichergröße insgesamt - @string/screen_settings_section_auto_photo_upload_toggle + Zwischenspeicher leeren Änderungen werden nach einem Neustart der App aktiv Registriert für - %1$s Intervall der Aktualisierungsprüfung Nach Aktualisierungen suchen Letzte Ausführung %1$s Noch nie Noch nie ~ Wenn aus technischen Gründen keine Update-Prüfung durchgeführt werden kann, können Updates manuell über die Website https://cryptomator.org/android/ heruntergeladen und installiert werden. - Zwischenspeichergröße pro Cloud - Sofort 1 Minute @@ -515,25 +351,15 @@ 5 Minuten 10 Minuten Nie - - 50 MB - 100 MB - 250 MB - 500 MB - 1 GB - 5 GB - Design Automatisch (System-Einstellung verwenden) Hell Dunkel - Einmal am Tag Einmal pro Woche Einmal im Monat @string/lock_timeout_never - diff --git a/presentation/src/main/res/values-es/strings.xml b/presentation/src/main/res/values-es/strings.xml index 43bd2c24..b871bcd9 100644 --- a/presentation/src/main/res/values-es/strings.xml +++ b/presentation/src/main/res/values-es/strings.xml @@ -1,10 +1,7 @@ - Cryptomator Cifrar - @string/app_name - Se ha producido un error Ha fallado la autenticación @@ -17,43 +14,31 @@ La nube ya existe. Por favor, descarga una aplicación que pueda abrir este archivo. Servidor no encontrado. - - - Crypto - Dropbox - Google Drive - OneDrive - WebDAV + + Almacenamiento local - - + + Cryptomator necesita acceso al almacenamiento para exportar archivos. Cryptomator necesita acceso al almacenamiento para subir archivos. Cryptomator necesita acceso al almacenamiento para compartir archivos. Configuración - - + + Añadir a Cryptomator Crear nueva caja fuerte Añadir caja fuerte existente - @string/screen_file_browser_node_action_rename Eliminar Haz clic aquí para crear una caja fuerte Contraseña cambiada con éxito - Caja fuerte - @string/screen_vault_list_action_add_existing_vault Seleccionar archivo masterkey - @string/screen_vault_list_action_create_new_vault Dejar aquí Nombre de caja fuerte: %1$s Mover Carpeta vacía - "%1$s + \"%1$s modificado hace %1$s Compartir con Elegir destino @@ -68,45 +53,31 @@ Compartir Renombrar Editar - @string/screen_file_browser_move_button_text Exportar Eliminar Sin conexión Reintentar - Guardado correctamente - Guardar %1$s en… texto archivo archivos Los nombres de archivo deben ser únicos. Renombra los duplicados. - @string/screen_share_files_content_files Guardar ubicación Guardar Cifrado completado - @string/dialog_file_name_placeholder - Servicio de nube - @string/screen_vault_list_action_add_existing_vault - @string/screen_vault_list_action_create_new_vault - Elegir ubicación - @string/screen_file_browser_node_action_edit_text - @string/screen_vault_list_vault_action_delete Haz clic aquí para añadir ubicaciones El servidor no parece ser compatible con WebDAV Ubicaciones personalizadas Almacenamiento predeterminado No hay ubicaciones extra disponibles. - - @string/cloud_names_webdav - URL Nombre de usuario Contraseña Conectar @@ -114,78 +85,53 @@ La URL no es válida. El nombre de usuario no puede estar vacio. La contraseña no puede estar vacía. - - @string/screen_vault_list_action_create_new_vault El nombre de la caja fuerte no puede estar vacío. Nombre de la caja fuerte Crear - Establecer contraseña - @string/screen_webdav_settings_msg_password_must_not_be_empty Las contraseñas no coinciden. Completado IMPORTANTE: si olvida su contraseña no habrá manera de recuperar los datos. - @string/screen_webdav_settings_password_label Reescriba la contraseña - - @string/snack_bar_action_title_settings - General Servicios de nube - @string/screen_webdav_settings_done_button_text Web de Cryptomator Síguenos en Twitter Danos me gusta en Facebook - https://cryptomator.org - https://facebook.com/Cryptomator - https://twitter.com/Cryptomator - Legal Licencias Términos de la licencia Soporte Solicitar ayuda - https://cryptomator.org/contact/ Modo de depuración Enviar archivo de trazas Error en el envío Versión - - @string/screen_settings_cloud_settings_label Conexiones de WebDAV Ubicaciones de almacenamiento local Iniciar sesión en Cerrar sesión de - - @string/screen_settings_licenses_label - - + No se pudo autenticar en %1$s. - No se llega a %1$s Cryptomator ha detectado que no se llega a esta carpeta - Más detalles sobre Sanitizer - - Cancelar - @string/screen_file_browser_action_create_folder - @string/screen_enter_vault_name_button_text - @string/screen_webdav_settings_password_label Desbloquear Antigua contraseña Nueva contraseña - @string/screen_set_password_retype_password_label Cambiar contraseña La antigua contraseña no puede estar vacía. La nueva contraseña no puede estar vacía. Las nuevas contraseñas no coinciden. + + Eliminar El archivo ya existe Reemplazar Ya existe un archivo llamado %1$s. @@ -195,34 +141,25 @@ Reemplazar Ya existe un archivo llamado %1$s. ¿Quieres reemplazarlo? Todos los archivos existen ya. ¿Quieres reemplazarlos? - "%d archivos existen ya. ¿Quieres reemplazarlos? - "¿Reemplazar archivo? - "¿Reemplazar archivos? + \"%d archivos existen ya. ¿Quieres reemplazarlos? + \"¿Reemplazar archivo? + \"¿Reemplazar archivos? No se puede compartir archivos No ha configurado ninguna caja fuerte. Cree antes una nueva caja fuerte con la aplicación Cryptomator. Aceptar Crear caja fuerte No se puede abrir %1$s - @string/screen_file_browser_node_action_export Descarga una aplicación que pueda abrir el archivo o, ¿quieres guardarlo en el dispositivo? Renombrar caja fuerte - @string/screen_file_browser_node_action_rename Renombrar carpeta Renombrar archivo - @string/screen_file_browser_node_action_rename Tienes cambios sin guardar - "¿De verdad quieres salir sin guardar? + \"¿De verdad quieres salir sin guardar? Descartar - @string/screen_share_files_save_button_text - @string/screen_file_browser_action_create_new_text_file - @string/screen_enter_vault_name_button_text - @string/dialog_button_cancel texto.txt - @string/screen_file_browser_node_action_delete - "¿Estás seguro de que quieres eliminar esta caja fuerte? + \"¿Estás seguro de que quieres eliminar esta caja fuerte? Esta acción solo eliminará la caja fuerte de esta lista y no la borrará físicamente. Sube… - @string/dialog_button_cancel Espera, por favor… Creando carpeta… Creando archivo de texto… @@ -241,37 +178,21 @@ El certificado SSL no es válido. ¿Quiere confiar en él de todas formas? El uso de HTTP no es seguro. Recomendamos usar HTTPS en su lugar. Si conoce los riesgos puede seguir usando HTTP. Cambiar a HTTPS - "¿Usar HTPPS? + \"¿Usar HTPPS? No se ha establecido el bloqueo de pantalla. Para almacenar las credenciales de forma segura, establece con Aceptar un patrón o contraseña. - "¿Establecer bloqueo de pantalla? + \"¿Establecer bloqueo de pantalla? Establecer bloqueo de pantalla Aviso Activar - @string/dialog_button_cancel - "¿Estás seguro de que quieres eliminar esta conexión de nube? + Aviso + \"¿Estás seguro de que quieres eliminar esta conexión de nube? Esta acción eliminará la conexión de nube y todas las cajas fuertes de esta nube. - @string/screen_file_browser_node_action_delete - @string/dialog_button_cancel - @string/screen_file_browser_node_action_delete - @string/dialog_button_cancel - "¿Estás seguro de que quieres borrar este archivo? + \"¿Estás seguro de que quieres borrar este archivo? Esto borrará todo el contenido de la carpeta. ¿Estás seguro de que quiere borrar esta carpeta? - - Informe de error de Android - Sumario - Introduce una descripción corta de lo has intentado hacer o indica el ticket de soporte si ya habías creado uno. - Información del dispositivo - - + + Cero kB - bytes - kB - MB - GB - TB - segundo segundos @@ -287,17 +208,20 @@ meses año años - + Cajas fuertes desbloqueadas: %1$d Autobloqueo en %1$s Bloquear todas - + \"%1$s 1 minuto 2 minutos 5 minutos 10 minutos Nunca - + + + + Nunca diff --git a/presentation/src/main/res/values-fr/strings.xml b/presentation/src/main/res/values-fr/strings.xml index 92575f57..ccdf0340 100644 --- a/presentation/src/main/res/values-fr/strings.xml +++ b/presentation/src/main/res/values-fr/strings.xml @@ -1,11 +1,7 @@ - - Cryptomator Chiffrer - @string/app_name - Une erreur est survenue Échec de l\'authentification @@ -29,29 +25,18 @@ Le mot de passe WebDAV n\'a pas été déchiffré, veuillez l\'ajouter une nouvelle fois dans les paramètres Services Google play non installés Authentification biométrique avortée - - - Crypto - Dropbox - Google Drive - OneDrive - WebDAV Stockage local - - Cryptomator a besoin de l\'accès au stockage pour exporter des fichiers Cryptomateur a besoin de l\'accès au stockage pour téléverser des fichiers Cryptomator a besoin de l\'accès au stockage pour partager des fichiers - Paramètres Rechercher Précédent Suivant - Trier par A - Z Z - A @@ -59,105 +44,74 @@ Plus ancien Taille décroissante Taille croissante - - Ajouter à Cryptomator Créer un nouveau coffre-fort Ajouter un coffre-fort existant - @string/screen_file_browser_node_action_rename Retirer Cliquez ici pour créer un nouveau coffre-fort Mot de passe modifié avec succès - Coffre - - @string/screen_vault_list_action_add_existing_vault Sélectionné le fichier de clé principal - @string/screen_vault_list_action_create_new_vault Placé ici Nom du coffre-fort: %1$s - Déplacé %1$s vers Déplacer des éléments de %2$s vers - Déplacer - Dossier vide %1$s Modifié il y à %1$s - Partager avec Choisissez la destination Choisir Rien à partager - Ajouter le %1$s Créer le dossier Créer le fichier texte Televerser des fichiers Fichiers - Fichier exporté Fichiers exportés Rien à exporter - Échec de la création du répertoire de téléchargement - Ouvrir avec… - Partager Renommer Éditer - @string/screen_file_browser_move_button_text Exporter Supprimer - + Ouvrir avec… Sélectionnez les éléments %1$d sélectionné Sélectionner… Tout sélectionner Rafraîchir - Aucune connection Réessayer - Enregistré avec succès - Enregistré %1$s vers… texte fichier fichiers - Les noms de fichiers doivent être uniques, veuillez renommer les doublons - @string/screen_share_files_content_files Enregistrer l\'emplacement Enregistrer Chiffrement terminé - @string/dialog_file_name_placeholder - Service cloud - @string/screen_vault_list_action_add_existing_vault - @string/screen_vault_list_action_create_new_vault - Choisissez l\'emplacement - @string/screen_file_browser_node_action_edit_text - @string/screen_vault_list_vault_action_delete Cliquez ici pour ajouter des emplacements Le serveur ne semble pas compatible avec WebDAV Emplacements personnalisés Stockage par défaut Aucun emplacement supplémentaire disponible. - - @string/cloud_names_webdav URL Nom d\'utilisateur Mot de passe @@ -166,31 +120,22 @@ URL invalide. Le nom d\'utilisateur ne peut pas être vide. Le mot de passe ne peut pas être vide. - - @string/screen_vault_list_action_create_new_vault Le nom du coffre-fort ne peut pas être vide. Nom du coffre-fort Créer - Définir le mot de passe - @string/screen_webdav_settings_msg_password_must_not_be_empty Le mot de passe ne correspond pas au mot de passe retapé. Terminé IMPORTANT: Si vous oubliez votre mot de passe, il n\'y aura aucun moyen de récupérer vos données. - @string/screen_webdav_settings_password_label Retaper le mot de passe - Très faible Faible Acceptable Fort Très fort - - @string/snack_bar_action_title_settings - Général Service cloud Authentification biométrique @@ -198,94 +143,63 @@ Confirmer le déverrouillage par reconnaissance faciale (si disponible) Bloquer l\'application lorsqu\'elle est masquée Sécurité de l\'écran - Recherche Recherche en direct Recherche avec le modèle glob - Verrouillage automatique Verrouillage après Lorsque l\'écran est éteint - Téléversement automatique de photo Choisir un coffre-fort pour le téléversement Activer Téléverser sur réseau WIFI uniquement - Enregistrer les fichiers du téléversement automatique dans… - - @string/screen_webdav_settings_done_button_text Site web de Cryptomator Suivez-nous sur Twitter Aimez notre page Facebook - https://cryptomator.org - https://facebook.com/Cryptomator - https://twitter.com/Cryptomator - Légal - Licenses + Licences Termes de la licence - - Support + Support technique Demander de l\'aide - https://cryptomator.org/contact/ Mode débogage Envoyer un fichier journal L\'envoi a échoué Conseils de sécurité - https://docs.cryptomator.org/en/1.5/security/best-practices/ - Version - Gardez les coffres déverrouillés lors de la modification des fichiers - + Paramètres Avancés + Préparations du déverrouillage en arrière-plan - @string/screen_settings_cloud_settings_label Connexions WebDAV Emplacements du stockage local Se connecter à Se déconnecter de - - @string/screen_settings_licenses_label - %1$s n\'a pas pu être authentifié. - \'%1$s\' inaccessible Cryptomator a détecté que ce dossier est inaccessible. Il a peut-être été supprimé par une autre application ou une synchronisation cloud défectueuse pourrait en être la cause.\n\nEssayez de restaurer le fichier de répertoire via votre fournisseur de cloud dans une version précédente qui n\'est pas vide. Le fichier en question est:\n%1$s\n\nSi cela ne fonctionne pas, vous pouvez utiliser Sanitizer pour rechercher des problèmes dans votre coffre-fort et éventuellement restaurer vos données. Plus de détails sur Sanitizer - - Annuler - - @string/screen_file_browser_action_create_folder - @string/screen_enter_vault_name_button_text - - @string/screen_webdav_settings_password_label Déverrouiller - Ancien mot de passe Nouveau mot de passe - @string/screen_set_password_retype_password_label Changer le mot de passe L\'ancien mot de passe ne peut pas être vide. Le nouveau mot de passe ne peut pas être vide. Le nouveau mot de passe ne correspond pas au mot de passe retapé. - Coffre-fort %1$s introuvable Le coffre-fort a été renommé, déplacé ou supprimé. Supprimez ce coffre-fort de la liste et ajoutez-le à nouveau pour continuer. Supprimer maintenant? Supprimer - Le fichier existe déjà Remplacer Un fichier nommé \'%1$s\' existe déjà. - Ignorer l\'existant Remplacer tout Remplacer existant @@ -295,44 +209,24 @@ %d fichiers existent déjà. Voulez-vous les remplacer? Remplacer le fichier? Remplacer les fichiers? - Impossible de partager des fichiers Vous n\'avez pas configuré de coffre-fort. Veuillez d\'abord créer un nouveau coffre-fort avec l\'application Cryptomator. OK Créer un coffre-fort - Impossible d\'ouvrir %1$s - @string/screen_file_browser_node_action_export Veuillez télécharger une application qui peut ouvrir ce fichier ou souhaitez-vous l\'enregistrer sur votre appareil? - Renommer le coffre-fort - @string/screen_file_browser_node_action_rename - Renommer le dossier Renommer le fichier - @string/screen_file_browser_node_action_rename - Vous avez des modifications non enregistrés Désirez-vous vraiment quitter sans enregistrer? Abandonner - @string/screen_share_files_save_button_text - - @string/screen_file_browser_action_create_new_text_file - @string/screen_enter_vault_name_button_text - @string/dialog_button_cancel texte.txt - - @string/screen_file_browser_node_action_delete Êtes-vous sûr de vouloir retirer ce coffre-fort? Cette action ne fera que retirer le coffre-fort de cette liste sans le supprimer physiquement. - Téléversement… - @string/dialog_button_cancel Fichier %1$d à %2$d - Exportation (%1$d/%2$d) - @string/dialog_button_cancel - Patientez s\'il vous plaît… Création du dossier… Création du fichier texte… @@ -348,104 +242,68 @@ Déchiffrement… Déplacement… Verouiller - Certificat SSL invalide Le certificat SSL n\'est pas valide. Vous voulez quand même lui faire confiance? Détails Cela pourrait constituer un risque pour la sécurité. Je sais ce que je fais. - L\'utilisation du HTTP n\'est pas sûre. Nous recommandons d\'utiliser plutôt le HTTPS. Si vous connaissez les risques, vous pouvez continuer à utiliser HTTP. Passage au HTTPS Utiliser le HTTPS? - Aucun verrouillage de l\'écran n\'est activé. Pour stocker vos informations d\'identification de manière sécurisée, définissez un schéma ou un mot de passe avec OK. Régler le verrouillage de l\'écran? Régler le verrouillage de l\'écran - Aucune authentification de base n\'est configurée dans le système Inscrivez au moins un doigt/visage pour utiliser ce service. - Dans ce mode, les données sensibles peuvent être écrites dans un fichier journal sur votre appareil (par exemple, les noms de fichiers et les chemins d\'accès). Les mots de passe, cookies, etc. sont explicitement exclus.\n\nN\'oubliez pas de désactiver le mode de débogage dès que possible. - Attention + Avertissement Activer - @string/dialog_button_cancel - Ce paramètre est une fonction de sécurité qui empêche les autres applications de tromper les utilisateurs en leur faisant faire des choses qu\'ils ne veulent pas faire.\n\nEn le désactivant, vous confirmez que vous êtes conscients des risques. - Attention + Avertissement Désactiver - @string/dialog_button_cancel - \'application est masquée Une autre application affiche quelque chose au-dessus de Cryptomator (par exemple, un filtre de lumière bleue ou une application forçant le mode nuit). Pour des raisons de sécurité, Cryptomator est désactivé.\n\nComment activer Cryptomator Fermer - Ce paramètre est une fonction de sécurité qui empêche les autres applications de tromper les utilisateurs en leur faisant faire des choses qu\'ils ne veulent pas faire.\n\nEn le désactivant, vous confirmez que vous êtes conscients des risques. - Êtes-vous sûr de vouloir supprimer cette connexion au cloud? Cette action retirera l\'accès à ce cloud et à tous les coffre-fort de celui-ci. - @string/screen_file_browser_node_action_delete - @string/dialog_button_cancel - - @string/screen_file_browser_node_action_delete - @string/dialog_button_cancel Supprimé %1$d éléments? Êtes-vous sûr de vouloir supprimer ces éléments? Êtes-vous sûr de vouloir supprimer ce fichier? Cela supprimera tout le contenu du dossier. Êtes-vous sûr de vouloir supprimer ce dossier? - Fonctionnalité d\'authentification biométrique désactivée La clé ayant été invalidée, la fonctionnalité d\'authentification biométrique a été désactivée. Pour la réactiver, ouvrez les paramètres de Cryptomator. - @string/dialog_unable_to_share_positive_button - Fournir une licence valide Nous avons détecté que vous avez installé Cryptomator sans utiliser le Play Store de Google. Fournissez une licence valide, qui peut être achetée sur https://cryptomator.org/android/ La licence fournie n\'est pas valide. Vérifiez que vous l\'avez saisie correctement. Aucune licence n\'est fournie. Veuillez saisir une licence valide. - @string/dialog_unable_to_share_positive_button Sortie - Confirmation de la licence Merci %1$s d\'avoir fourni votre licence valide. - @string/dialog_unable_to_share_positive_button - + Mise à jour disponible Mettez à jour Cryptomator vers la dernière version. En appuyant sur OK, nous téléchargerons l\'application en arrière-plan et vous proposerons de l\'installer. Mettre à jour maintenant Accéder au site de téléchargements Plus tard - Téléchargement en cours Téléchargement de la dernière version de Cryptomator - Le dossier est un lien symbolique Vous ne pouvez pas naviguer dans ce lien symbolique Retour - Impossible de charger le contenu du répertoire Le dossier cloud \'%1$s\' n\'a pas de fichier de répertoire. Il se peut que le dossier ait été créé sur un autre appareil et qu\'il n\'ait pas encore été entièrement synchronisé avec le cloud. Veuillez vérifier dans votre cloud si le fichier suivant existe: \n%2$s - @string/dialog_sym_link_back_button - Version bêta Il s\'agit d\'une version bêta qui introduit la prise en charge du format de coffre-fort vault 7. Veuillez vous assurer que vous n\'utilisez pas votre coffre-fort principal pour les tests ou que vous disposez d\'une bonne stratégie de sauvegarde. - Cryptomator a besoin de l\'accès au stockage pour utiliser les coffres locaux Cryptomator a besoin de l\'accès au stockage pour effectuer le téléversement automatique de photos - - Rapport d\'erreur Android - Résumé - Insérez une courte description de ce que vous avez essayé de faire ou mentionnez votre ticket d\'assistance si vous en avez déjà créé un. - Informations sur l\'appareil - - - Zero kB - bytes - kB - MB - GB - TB - + Zéro Ko + octets + ko + Mo + Go + To seconde secondes @@ -461,54 +319,39 @@ mois année années - Identification biométrique Connectez-vous à l\'aide de votre identifiant biométrique Utiliser le mot de passe du coffre-fort - - "Impossible de téléverser automatiquement les fichiers" - + Impossible de téléverser automatiquement les fichiers Coffre-fort déverrouillées: %1$d Verrouillage automatique dans %1$s Tout verrouiller - Annuler le téléversement Téléversement auto de photos en cours Téléversement %1d/%2d - Téléversement auto des photos terminé %1$d images téléversées dans le coffre-fort - Échec du téléversement auto des photos Une erreur générale s\'est produite lors du téléversement. Le dossier sélectionné pour le téléversement n\'est plus disponible. Accédez aux paramètres et choisissez-en un nouveau Coffre-fort verrouillé pendant le téléchargement, veuillez rouvrir le coffre-fort pour continuer - - @string/dialog_button_cancel Ouvrir un fichier accessible en écriture Le coffre-fort reste déverrouillé jusqu\'à la fin des modifications - Dernière version installée - Cache - @string/screen_settings_section_auto_photo_upload_toggle Taille totale du cache Vider le cache Les changements seront appliqués lors du prochain démarrage de l\'application - Enregistré pour %1$s - Intervalle de vérification des mises à jour Vérifier les mises à jour Dernière exécution %1$s @string/lock_timeout_never Jamais ~ Si la vérification de mise à jour ne peut être effectué pour des raisons techniques, les mises à jour peuvent être téléchargées et installées manuellement à partir du site https://cryptomator.org/android/. - Taille du cache par cloud - Instantané 1 minute @@ -516,26 +359,21 @@ 5 minutes 10 minutes Jamais - - 50 MB - 100 MB - 250 MB - 500 MB - 1 GB - 5 GB - + 50 Mo + 100 Mo + 250 Mo + 500 Mo + 1 Go + 5 Go - Style + Aspect Automatique (suivre le système) Clair Sombre - Une fois par jour Une fois par semaine Une fois par mois - Mise à jour disponible @string/lock_timeout_never - diff --git a/presentation/src/main/res/values-he/strings.xml b/presentation/src/main/res/values-he/strings.xml new file mode 100644 index 00000000..e5a9e06b --- /dev/null +++ b/presentation/src/main/res/values-he/strings.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/presentation/src/main/res/values-night/styles.xml b/presentation/src/main/res/values-night/styles.xml index 48f2ba33..8581a6e2 100644 --- a/presentation/src/main/res/values-night/styles.xml +++ b/presentation/src/main/res/values-night/styles.xml @@ -66,8 +66,8 @@ 48dp 16sp match_parent - 16dp - 16dp + 16dp + 16dp 16dp 32dp true diff --git a/presentation/src/main/res/values-tr/strings.xml b/presentation/src/main/res/values-tr/strings.xml index be04b658..c74cf321 100644 --- a/presentation/src/main/res/values-tr/strings.xml +++ b/presentation/src/main/res/values-tr/strings.xml @@ -1,11 +1,7 @@ - - Cryptomator Şifrele - @string/app_name - Bir hata oluştu Kullanıcı adı veya şifre yanlış @@ -29,136 +25,90 @@ WebDAV şifresi çözülemedi, lütfen ayarlara yeniden ekleyin Play Hizmetleri yüklü değil Biyometrik kimlik doğrulama iptal edildi - - - Kripto - Dropbox - Google Drive - OneDrive - WebDAV Yerel depolama - - Cryptomator\'un dosyaları dışa aktarmak için depolama erişimine ihtiyacı var Cryptomator\'un dosyaları yüklemek için depolama erişimine ihtiyacı var Cryptomator\'un dosyaları paylaşmak için depolama erişimine ihtiyacı var - Ayarlar Ara Önceki Sonraki - Sırala - A - Z - Z - A Önce en yenisi Önce en eskisi Önce en büyüğü Önce en küçüğü - - Cryptomator\'a ekle Yeni kasa oluştur Mevcut kasayı ekle - @string/screen_file_browser_node_action_rename Kaldır Kasa oluşturmak/eklemek için burayı tıklayın Şifre başarıyla değiştirildi - Kasa - - @string/screen_vault_list_action_add_existing_vault Ana anahtar dosyasını seçin - @string/screen_vault_list_action_create_new_vault Buraya kaydet Kasa adı: %1$s - %1$s öğesini şuraya taşı %2$d öğeyi şuraya taşı - Taşı - Boş - %1$s %1$s önce değiştirildi - İle paylaş Bir varış noktası seçin Seç Paylaşacak bir şey yok - %1$s listesine ekle Klasör oluştur Metin dosyası oluştur Dosya yükle Dosyalar - Dosya başarıyla dışa aktarıldı Dosyalar başarıyla dışa aktarıldı Dışa aktarılacak bir şey yok - İndirme dizini oluşturulamadı - Paylaş Yeniden adlandır Düzenle - @string/screen_file_browser_move_button_text Dışa aktar Sil Bununla aç… - Öğeleri seç %1$d seçildi Seç… Tümünü seç Yenile - Bağlantı yok Yeniden dene - Başarıyla kaydedildi - %1$s kaydet… Metin Dosya Dosyalar - Dosya adları benzersiz olmalıdır, lütfen kopyaları yeniden adlandırın. - @string/screen_share_files_content_files Konumu kaydet Kaydet Şifreleme tamamlandı - @string/dialog_file_name_placeholder - Bulut hizmeti - @string/screen_vault_list_action_add_existing_vault - @string/screen_vault_list_action_create_new_vault - Bir yer seçin - @string/screen_file_browser_node_action_edit_text - @string/screen_vault_list_vault_action_delete Konum eklemek için + butonunu tıklayın Sunucu WebDAV uyumlu görünmüyor Özel konumlar Varsayılan depolama Kullanılabilir ek konum yok. - - @string/cloud_names_webdav - URL Kullanıcı adı Parola Bağlan @@ -166,31 +116,22 @@ URL geçersiz. Kullanıcı adı boş olamaz. Parola boş olamaz. - - @string/screen_vault_list_action_create_new_vault Kasa adı boş olamaz. Kasa adı Oluştur - Şifreyi belirle - @string/screen_webdav_settings_msg_password_must_not_be_empty Parola, yeniden yazılan parolayla eşleşmiyor. Bitti ÖNEMLİ UYARI: Parolanızı unutursanız, verilerinizi kurtarmanın herhangi bir yolu yoktur. - @string/screen_webdav_settings_password_label Yeni şifreyi tekrar yazın - Çok zayıf Güçsüz Makul Kuvvetli Çok güçlü - - @string/snack_bar_action_title_settings - Genel Kaydetme konumları Biyometrik kimlik doğrulama @@ -201,93 +142,60 @@ Arama Canlı arama Glob kalıbı kullanarak ara - Otomatik Kilitleme Kilitleme zamanı Ekran devre dışı bırakıldığında - Otomatik Fotoğraf Yükleme Yükleme için kasa seçin Etkinleştir Yalnızca WIFI kullanarak yükle - Otomatik yükleme… - - @string/screen_webdav_settings_done_button_text Cryptomator web sitesi Bizi Twitter\'da takip edin Bizi Facebook\'ta beğenin - https://cryptomator.org - https://facebook.com/Cryptomator - https://twitter.com/Cryptomator - Yasal Lisanslar Lisans şartları - Destek Yardım isteyin - https://cryptomator.org/contact/ Hata ayıklama modu Günlük dosyası gönder Gönderim başarısız oldu Güvenlik ipuçları - https://docs.cryptomator.org/en/1.5/security/best-practices/ - Sürüm - Düzenlerken kasa kilidi açık - Gelişmiş Ayarlar Arka planda kilit açma - - @string/screen_settings_cloud_settings_label WebDAV bağlantıları Yerel depolama konumları Giriş Oturumunu kapat - - @string/screen_settings_licenses_label - %1$s kimliği doğrulanamadı. - \'%1$s\' ulaşılamaz Cryptomator bu klasöre erişilemediğini tespit etti. Dizin dosyasını bulut sağlayıcınız aracılığıyla boş olmayan önceki bir sürüme geri yüklemeyi deneyin. Söz konusu dosya:\n%1$s\n\nBu işe yaramazsa, kasanızı sorunlar için kontrol etmek ve muhtemelen verilerinizi geri yüklemek için Sanitizer\'ı kullanabilirsiniz. Sanitizer Hakkında Daha Fazla Bilgi - - İptal - - @string/screen_file_browser_action_create_folder - @string/screen_enter_vault_name_button_text - - @string/screen_webdav_settings_password_label Kilidi Aç - Eski şifre Yeni şifre - @string/screen_set_password_retype_password_label Şifreyi değiştir Eski şifre boş olamaz. Yeni şifre boş olamaz. Yeni parola, parola tekrarı ile eşleşmiyor. - %1$s kasası bulunamadı Kasa yeniden adlandırılmış, taşınmış veya silinmiş olabilir. Bu kasayı listeden çıkarın ve devam etmek için tekrar ekleyin. Şimdi kaldırılsın mı? Kaldır - Dosya zaten mevcut Değiştir \'%1$s\' adlı bir dosya zaten var. - Var olanı atla Tümünü değiştir Var olanı değiştir @@ -297,44 +205,24 @@ %d dosya zaten var. Onları değiştirmek ister misin? Dosya değiştirilsin mi? Dosyalar değiştirilsin mi? - Dosyalar paylaşılamıyor Daha önce herhangi bir kasa oluşturmadınız! Önce Cryptomator uygulamasıyla yeni bir kasa oluşturun lütfen. Tamam Kasa oluştur - %1$s açılamıyor - @string/screen_file_browser_node_action_export Lütfen bu dosyayı açabilecek bir uygulama indirin veya cihazınıza kaydetmek ister misiniz? - Kasayı yeniden adlandır - @string/screen_file_browser_node_action_rename - Dosyayı yeniden adlandır Dosyayı yeniden adlandır - @string/screen_file_browser_node_action_rename - Kaydedilmemiş değişiklikleriniz mevcut Kaydetmeden çıkmak istiyor musunuz? Gözardı et - @string/screen_share_files_save_button_text - - @string/screen_file_browser_action_create_new_text_file - @string/screen_enter_vault_name_button_text - @string/dialog_button_cancel metin.txt - - @string/screen_file_browser_node_action_delete Bu kasayı kaldırmak istediğinizden emin misiniz? Bu işlem kasayı yalnızca bu listeden kaldıracak ve fiziksel olarak silmeyecektir. - Yükleniyor… - @string/dialog_button_cancel %1$d / %2$d dosyası - Dışa aktarılıyor (%1$d/%2$d) - @string/dialog_button_cancel - Lütfen bekleyin… Klasör oluşturuluyor… Metin dosyası oluşturuluyor… @@ -350,105 +238,65 @@ Şifre çözülüyor… Taşınıyor… Kilitle - Geçersiz SSL sertifikası SSL sertifikası geçersiz. Yine de güvenmek istiyor musun? Detaylar Bu bir güvenlik riski olabilir! Ne yaptığımı biliyorum. - HTTP\'nin kullanımı güvensizdir. Bunun yerine HTTPS kullanmanızı öneririz. Riskleri biliyorsanız, HTTP ile devam edebilirsiniz. HTTPS\'ye geç HTTPS kullanılsın mı? - Ekran kilidi ayarlanmadı. Kimlik bilgilerinizi güvenli bir şekilde saklamak için, Tamam ile bir kalıp veya şifre ayarlayınız. Ekran kilidi ayarlansın mı? Ekran kilidini ayarla - Sistemde temel kimlik doğrulama kurulumu yok Bu hizmeti kullanmak için en az bir parmağınızı/yüzünüzü kaydedin. - Bu modda, hassas veriler cihazınızdaki bir günlük dosyasına (örn. Dosya adları ve yolları) yazılabilir. Şifreler, tanımlama vb. bilgiler hariç tutulmuştur.\n\nHata ayıklama modunu mümkün olan en kısa sürede devre dışı bırakmayı unutmayın. Dikkat Etkinleştir - @string/dialog_button_cancel - Bu ayar bir güvenlik özelliğidir ve diğer uygulamaların, kullanıcıları kandırmasını engeller.\n\nDevre dışı bırakarak, risklerin farkında olduğunuzu onaylamış olursunuz. Dikkat Devre dışı bırak - @string/dialog_button_cancel - Uygulama gizlendi Cryptomator\'un üstünde çalışan bazı uygulamalar, (örn. Mavi ışık filtresi ve gece modu uygulamaları gibi) içeriği görüntüler! Bu nedenden dolayı, güvenlik amacıyla Cryptomator devre dışı bırakılır!\n\nCryptomator\'u tekrar nasıl etkinleştirebilirim? Kapat - Bu ayar bir güvenlik özelliğidir ve diğer uygulamaların, kullanıcıları kandırmasını engeller.\n\nDevre dışı bırakarak, risklerin farkında olduğunuzu onaylamış olursunuz. - Bu bulut bağlantısını kaldırmak istediğinizden emin misiniz? Bu işlem, bulut bağlantısını ve bu bulutun tüm kasalarını kaldıracak. - @string/screen_file_browser_node_action_delete - @string/dialog_button_cancel - - @string/screen_file_browser_node_action_delete - @string/dialog_button_cancel %1$d öğe silinsin mi? Bu öğeleri silmek istediğinizden emin misiniz? Bu dosyayı silmek istediğinizden emin misiniz? Klasördeki tüm içerikler silinecek! Bu klasörü silmek istediğinizden emin misiniz? - Biyometrik kimlik doğrulama özelliği devre dışı bırakıldı Anahtar geçersiz olduğu için biyometrik kimlik doğrulama özelliği devre dışı bırakıldı. Yeniden etkinleştirmek için Cryptomator ayarlarını açın. - @string/dialog_unable_to_share_positive_button - Geçerli bir lisans sağlayın Cryptomator\'u Google Play Store kullanmadan yüklediğinizi tespit ettik. https://cryptomator.org/android/ adresinden satın alınabilecek geçerli bir lisans edinin lütfen. Sağlanan lisans geçerli değil. Doğru girdiğinizden emin olun. Lisans verilmemiştir. Lütfen geçerli bir lisans girin. - @string/dialog_unable_to_share_positive_button Çıkış - Lisans onayı Geçerli lisansınızı sağladığınız için teşekkür ederiz %1$s. - @string/dialog_unable_to_share_positive_button - Güncelleme uygun Cryptomator\'ı en son sürüme güncellemek için Tamam\'a dokunun lütfen. Uygulamayı arka planda indireceğiz ve sizden yüklemenizi isteyeceğiz. Şimdi güncelle İndirme sitesine git Sonra - Çalışmayı indir Cryptomator\'ın son sürümünü indir - Klasör sembolik bir bağlantıdır Bu sembolik bağlantıya gidemezsin Geri - Dizinin içeriği yüklenemiyor \'%1$s\' bulut klasörünün bir dizin dosyası yok. Klasör başka bir cihazda oluşturulmuş ve henüz buluta tam olarak senkronize edilmemiş olabilir. Lütfen aşağıdaki dosyanın mevcut olup olmadığını kontrol edin:\n%2$s - @string/dialog_sym_link_back_button - Beta sürümü Bu, kasa formatı 7 desteğini tanıtan bir beta sürümüdür. Lütfen test için önemli kasanızı kullanmadığınızdan veya iyi bir yedekleme stratejisine sahip olmadığınızdan emin olun. - Cryptomator\'un yerel kasaları kullanmak için depolama erişimine ihtiyacı var Cryptomator\'un otomatik fotoğraf yüklemesi için depolama erişimine ihtiyacı var - - Android Error Report - Summary - Insert a short description of what you tried to do or mention your support ticket if you already created one. - Device Info - - Sıfır KB bayt KB - MB - GB - TB - sn sn @@ -464,54 +312,38 @@ ay yıl yıl - Biyometrik giriş Biyometrik kimlik bilgilerinizi kullanarak giriş yapın Kasa şifresini kullan - Dosyaları otomatik olarak yükleyemiyor - Kasaların Kilidi Açıldı: %1$d %1$s içinde otomatik kilitlenecek Tümünü kilitle - Yüklemeyi iptal et Otomatik fotoğraf yükleme çalışıyor %1d/%2d yükleniyor - Otomatik fotoğraf yükleme tamamlandı Kasaya %1$d görüntü yüklendi - Otomatik fotoğraf yükleme başarısız oldu Yükleme sırasında genel hata oluştu. Yükleme için seçilen klasör artık mevcut değil! Ayarlara gidin ve yeni bir tane seçin Kasa yükleme sırasında kilitlendi, devam etmek için kasayı yeniden açın lütfen - - @string/dialog_button_cancel Yazılabilir dosyayı aç Düzenleme tamamlanana kadar, uygulamalar kasası kilidi açık kalır - En son sürüm yüklendi - Önbellek - @string/screen_settings_section_auto_photo_upload_toggle Toplam önbellek boyutu Önbelleği temizle Değişiklikler, uygulama yeniden başlatıldığında uygulanacak - Kayıtlı - %1$s - Kontrol aralığını güncelle Güncellemeleri kontrol et Son çalıştırma %1$s @string/lock_timeout_never Teknik nedenlerle güncelleme kontrolü yapılamıyorsa, güncellemeler, https://cryptomator.org/android/ web sitesinden manuel olarak indirilebilir ve yüklenebilir. - Bulut başına önbellek boyutu - Anında 1 dakika @@ -519,25 +351,15 @@ 5 dakika 10 dakika Asla - - 50 MB - 100 MB - 250 MB - 500 MB - 1 GB - 5 GB - Görünüm modu Otomatik Aydınlık Karanlık - Günde bir Haftada bir Ayda bir @string/lock_timeout_never - diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index 8a7dbf69..fa95a7bd 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -4,9 +4,9 @@ - Cryptomator + Cryptomator + @string/app_name Encrypt - @string/app_name An error occurred @@ -35,11 +35,11 @@ - Crypto - Dropbox - Google Drive - OneDrive - WebDAV + Crypto + Dropbox + Google Drive + OneDrive + WebDAV Local storage @@ -219,9 +219,9 @@ Cryptomator website Follow us on Twitter Like us on Facebook - https://cryptomator.org - https://facebook.com/Cryptomator - https://twitter.com/Cryptomator + https://cryptomator.org + https://facebook.com/Cryptomator + https://twitter.com/Cryptomator Legal Licenses @@ -229,12 +229,12 @@ Support Request help - https://cryptomator.org/contact/ + https://cryptomator.org/contact/ Debug mode Send log file Sending failed Security hints - https://docs.cryptomator.org/en/1.5/security/best-practices/ + https://docs.cryptomator.org/en/1.5/security/best-practices/ Version @@ -436,10 +436,10 @@ Cryptomator needs storage access to use auto photo upload - Android Error Report - Summary - Insert a detailed description of what you tried to do or mention your support ticket if you already created one. - Device Info + Android Error Report + Summary + Insert a detailed description of what you tried to do or mention your support ticket if you already created one. + Device Info diff --git a/presentation/src/main/res/values/styles.xml b/presentation/src/main/res/values/styles.xml index 3def9466..a09be1b3 100644 --- a/presentation/src/main/res/values/styles.xml +++ b/presentation/src/main/res/values/styles.xml @@ -66,8 +66,8 @@ 48dp 16sp match_parent - 16dp - 16dp + 16dp + 16dp 16dp 32dp true diff --git a/presentation/src/main/res/xml/preferences.xml b/presentation/src/main/res/xml/preferences.xml index 73acc427..06bf28c2 100644 --- a/presentation/src/main/res/xml/preferences.xml +++ b/presentation/src/main/res/xml/preferences.xml @@ -21,7 +21,7 @@ + android:targetPackage="@string/app_id" /> @@ -32,7 +32,7 @@ + android:targetPackage="@string/app_id" /> @@ -117,7 +117,7 @@ + android:targetPackage="@string/app_id" /> @@ -204,7 +204,7 @@ + android:targetPackage="@string/app_id" /> diff --git a/presentation/src/main/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt b/presentation/src/notFoss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt similarity index 100% rename from presentation/src/main/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt rename to presentation/src/notFoss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt diff --git a/secrets.properties b/secrets.properties deleted file mode 100644 index b8f2b15a..00000000 --- a/secrets.properties +++ /dev/null @@ -1,3 +0,0 @@ -ONEDRIVE_API_KEY= -DROPBOX_API_KEY= -DROPBOX_API_KEY_DB= diff --git a/subsampling-scale-image-view b/subsampling-scale-image-view index 951e3924..e9d0f187 160000 --- a/subsampling-scale-image-view +++ b/subsampling-scale-image-view @@ -1 +1 @@ -Subproject commit 951e3924349ec1607ed06663d32ec918abf09076 +Subproject commit e9d0f18740f00f55195811373791ea826f3c6ba3