Compare commits

...

75 Commits

Author SHA1 Message Date
Manav
ae1986d7d3 Merge pull request #43 from ente-io/bump-build-number
1.0.25 (26)
2023-01-28 15:43:00 +05:30
Manav
3b6648074a 1.0.25 (26) 2023-01-28 15:42:03 +05:30
Manav
a90f7e6abc Merge pull request #42 from ente-io/document-releases
Document automated releases
2023-01-28 15:37:37 +05:30
Manav
55722dd818 Merge pull request #41 from ente-io/playstore-submit
Upload to Google Play from GitHub action
2023-01-28 15:37:25 +05:30
Manav
7666c4e053 Document automated releases 2023-01-28 15:34:21 +05:30
Manav
cb93a0658f Use direct path
Removes the dependency of this build step on the previous build step.
2023-01-28 14:58:47 +05:30
Manav
97f665e8cf Remove unneeded mapping files 2023-01-28 14:57:55 +05:30
Manav
99516650fe Fix path 2023-01-28 14:01:10 +05:30
Manav
3928ccc6b7 Build a playstore variants 2023-01-28 13:49:42 +05:30
Manav
699f906843 Skeleton for upload-google-play 2023-01-28 13:39:24 +05:30
Manav
ca809a0e0b Merge pull request #40 from ente-io/apply-bis
Enable the BIS self classification flag
2023-01-28 13:02:18 +05:30
Manav
d52e0ed04a Enable the BIS self classification flag
We've submitted the BIS self classification report for the auth app alongwith
the photos app. More details: https://github.com/ente-io/photos-app/issues/427
2023-01-28 12:59:19 +05:30
Neeraj Gupta
c9936d68c1 Merge pull request #38 from ente-io/use_en_as_default
Restrict to en locale
2023-01-28 12:30:40 +05:30
Neeraj Gupta
59cfc88b4e Merge pull request #39 from ente-io/ua741-patch-1
Fix typo in read me
2023-01-28 12:14:15 +05:30
Neeraj Gupta
39f9385c74 Fix typo in read me 2023-01-28 12:13:16 +05:30
Neeraj Gupta
2017506b28 bump version to 1.0.25+25 2023-01-28 12:06:01 +05:30
Neeraj Gupta
1497866597 Restrict locale to en 2023-01-28 12:05:31 +05:30
Neeraj Gupta
78c12b5ee2 Merge pull request #35 from ente-io/24 2023-01-27 17:22:51 +05:30
Vishnu Mohandas
64159434d0 Merge pull request #36 from ente-io/xcloud 2023-01-26 16:39:23 +05:30
vishnukvmd
8bd1c1ec50 Update build script 2023-01-26 14:57:24 +05:30
vishnukvmd
409e9c39ca Update build file 2023-01-26 14:51:06 +05:30
vishnukvmd
73bd24da95 Add post clone CI script 2023-01-26 14:51:00 +05:30
vishnukvmd
aeb2f46a4f v1.0.24 2023-01-26 14:04:13 +05:30
vishnukvmd
cc9f8db288 Update build files 2023-01-26 14:04:06 +05:30
Vishnu Mohandas
83c70f0f6b Merge pull request #32 from ente-io/recents
Remove option to remove app from recents
2023-01-08 16:51:01 +05:30
Vishnu Mohandas
91fffc8b04 Merge pull request #31 from ente-io/tweak-trailing-margin-theme-picker
Increase trailing margin for the theme picker selection checkmark
2023-01-08 16:47:31 +05:30
Vishnu Mohandas
50b583c2d7 Merge pull request #30 from ente-io/use-newer-alternative
Use `AppLocalizations.localizationsDelegates` in other MaterialApp
2023-01-08 16:47:07 +05:30
vishnukvmd
0034da064f Remove option to remove app from recents 2023-01-08 16:38:04 +05:30
Manav
4fa61f0997 Use AppLocalizations.localizationsDelegates in other MaterialApp
Smoke tested by running the app on iOS simulator
2023-01-08 16:26:36 +05:30
Vishnu Mohandas
29bc7bb78f Merge pull request #29 from ente-io/fix-change-email-i18n-crash
Fix the crash on opening change email dialog
2023-01-08 16:16:55 +05:30
Manav
1df7d8de46 Fix the crash on opening change email dialog
The crash was happening in the `context.l10n` line in the
change_email_dialog.dart. This was because the root MaterialApp created by
AppLock wasn't being passed the AppLocalizations object.

Tested:
- Was able to reproduce the crash on iOS simulator (null check assertion)
- After the change, the crash doesn't happen
2023-01-08 16:05:40 +05:30
Manav
435fd6a1e7 Increase trailing margin for the theme picker selection checkmark 2023-01-08 15:26:05 +05:30
Vishnu Mohandas
c0f450d380 Merge pull request #27 from ente-io/reduce-cla-spam 2023-01-06 15:17:31 +05:30
Manav
9f686d38ed Run the CLA bot only on comments to PR
Right now, it unnecessarily runs and sends an email when customers open issues.

Not tested, but can test it by opening an issue after this is merged.

Reference:
- https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#issue_comment
2023-01-06 15:15:10 +05:30
Vishnu Mohandas
8ade294d7a Merge pull request #26 from ente-io/fix_typo
Fix copy
2022-12-31 11:30:57 +05:30
vishnukvmd
b5f3694805 Fix copy 2022-12-31 11:30:19 +05:30
Manav
1b1df0aa37 Merge pull request #25 from MalteKiefer/hotfix/german_language
fixed a forgotten string
2022-12-28 12:37:10 +05:30
Malte Kiefer
25dd92bdf0 fixed a forgotten string 2022-12-28 08:05:26 +01:00
Manav
e3ddc10a00 Merge pull request #24 from MalteKiefer/feature/language_german
translate app to german
2022-12-28 12:24:16 +05:30
Malte Kiefer
d0ae1ce566 translate app to german 2022-12-28 07:36:07 +01:00
Neeraj Gupta
b0eb0413f0 Separate icon config for fdroid 2022-12-18 08:59:05 +05:30
Neeraj Gupta
60a66efa79 Add fdroid flavor 2022-12-18 07:11:55 +05:30
Neeraj Gupta
e7c8437478 Merge branch 'main' of github.com:ente-io/auth 2022-12-18 06:43:35 +05:30
Neeraj Gupta
21ca31c1f3 Add fastlane details 2022-12-18 06:42:54 +05:30
Vishnu Mohandas
0330982eb0 Merge pull request #19 from ente-io/fix_window_manager_warning
Update warning dialog when "Hide from recents" is enabled
2022-12-15 22:36:19 +05:30
vishnukvmd
5fec321267 Update the warning copy since not all ROMs may block capturing of screenshots once FLAG_SECURE is set 2022-12-15 22:34:48 +05:30
Vishnu Mohandas
ca378d31d2 Merge pull request #17 from ente-io/ua741-patch-1 2022-12-15 14:08:33 +05:30
Neeraj Gupta
aedde8e447 Readme: Fix link to issues 2022-12-15 13:47:24 +05:30
Vishnu Mohandas
1f090ce3af Merge pull request #16 from ente-io/independent
Merge Independent APK track
2022-12-14 14:55:27 +05:30
vishnukvmd
308cf250fd v1.0.23 2022-12-14 14:43:20 +05:30
vishnukvmd
9ef9c3b9fd Migrate to open_filex 2022-12-14 14:43:05 +05:30
vishnukvmd
8e39b6f359 Merge branch 'main' into independent 2022-12-14 14:24:04 +05:30
vishnukvmd
05955e2e76 Update .gitignore 2022-12-14 14:23:51 +05:30
vishnukvmd
3bc9b46d4d Merge branch 'main' into independent 2022-12-14 14:16:39 +05:30
Vishnu Mohandas
38a6e5a99c Merge pull request #15 from ente-io/upgrade_dependencies
Upgrade dependencies
2022-12-14 14:16:03 +05:30
vishnukvmd
89dc0f81ed v1.0.22 2022-12-14 13:46:33 +05:30
vishnukvmd
24de1c6af7 Upgrade file_picker and flutter_sodium 2022-12-14 13:46:14 +05:30
Vishnu Mohandas
ee6c4d3744 Fix hyperlink to Download 2022-12-12 20:29:50 +05:30
Vishnu Mohandas
4e46a6f222 Merge pull request #14 from ente-io/readme-tweaks 2022-12-12 18:34:28 +05:30
Manav
563fb2fb7c README tweaks 2022-12-12 18:30:32 +05:30
Manav
216499d0a6 Merge pull request #13 from ente-io/extract-more-strings
Extract more strings into ARB files for localization
2022-12-12 18:11:02 +05:30
Manav
daf48befff Merge pull request #12 from ente-io/remove-test-file
Remove test file
2022-12-12 17:31:47 +05:30
Manav
359dc09d6a Extract more strings into ARB files for localization 2022-12-12 17:30:37 +05:30
Neeraj Gupta
73989998e9 Remove test file 2022-12-12 14:44:54 +05:30
Manav
0894a7eb36 Merge pull request #11 from ente-io/add-cla
Add CLA
2022-12-12 14:20:57 +05:30
Manav
550a955c1a Add CLA 2022-12-12 14:17:14 +05:30
Manav
598fb7856c Merge pull request #9 from ente-io/test-clabot
Testing CLA bot
2022-12-12 13:27:51 +05:30
Manav
b0d89cc568 Configure cla-assistant 2022-12-12 11:58:26 +05:30
Manav
e4eacb684f Test commit 2022-12-12 10:48:18 +05:30
Manav
6717f739ae Testing CLA bot 2022-12-12 10:40:15 +05:30
Vishnu Mohandas
00372208a4 Update Architecture folder structure 2022-12-09 21:50:36 +05:30
Vishnu Mohandas
7c093ec8c8 Update README 2022-12-09 21:46:31 +05:30
vishnukvmd
86be8482b7 Merge branch 'main' into independent 2022-11-28 13:07:08 +05:30
vishnukvmd
3e49cfbe5f Merge branch 'main' into independent 2022-11-28 13:06:41 +05:30
vishnukvmd
02ffe72cca Revert "Disable OpenFile to please PlayStore overlords"
This reverts commit a5cac1579b.
2022-11-24 16:15:24 +05:30
64 changed files with 951 additions and 552 deletions

View File

@@ -2,69 +2,85 @@ name: Flutter CI
# This workflow is triggered on pushes to the repository.
on:
workflow_dispatch:
# Enable manual run
push:
# Sequence of patterns matched against refs/tags
tags:
- 'v*' # Push events to matching v*, i.e. v4.2.0
workflow_dispatch:
# Enable manual run
push:
# Sequence of patterns matched against refs/tags
tags:
- "v*" # Push events to matching v*, i.e. v4.2.0
jobs:
build:
# This job will run on ubuntu virtual machine
runs-on: ubuntu-latest
steps:
build:
# This job will run on ubuntu virtual machine
runs-on: ubuntu-latest
steps:
# Setup Java environment in order to build the Android app.
- uses: actions/checkout@v2
- uses: actions/setup-java@v2
with:
distribution: "adopt"
java-version: "11"
# Setup Java environment in order to build the Android app.
- uses: actions/checkout@v2
- uses: actions/setup-java@v2
with:
distribution: 'adopt'
java-version: '11'
# Setup the flutter environment.
- uses: subosito/flutter-action@v2
with:
channel: "stable"
flutter-version: "3.3.8"
# Setup the flutter environment.
- uses: subosito/flutter-action@v2
with:
channel: 'stable'
flutter-version: '3.3.8'
# Fetch sub modules
- run: git submodule update --init --recursive
# Fetch sub modules
- run: git submodule update --init --recursive
# Get flutter dependencies.
- run: flutter pub get
# Get flutter dependencies.
- run: flutter pub get
- name: Setup keys
uses: timheuer/base64-to-file@v1
with:
fileName: "keystore/ente_auth_key.jks"
encodedString: ${{ secrets.SIGNING_KEY }}
- name: Setup keys
uses: timheuer/base64-to-file@v1
with:
fileName: 'keystore/ente_auth_key.jks'
encodedString: ${{ secrets.SIGNING_KEY }}
# Build independent apk.
- name: Build
run: flutter build apk --release --flavor independent && mv build/app/outputs/flutter-apk/app-independent-release.apk build/app/outputs/flutter-apk/ente-auth.apk
env:
SIGNING_KEY_PATH: "/home/runner/work/_temp/keystore/ente_auth_key.jks"
SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }}
SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }}
SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_STORE_PASSWORD }}
# Build independent apk.
- name: Build
run: flutter build apk --release --flavor independent && mv build/app/outputs/flutter-apk/app-independent-release.apk build/app/outputs/flutter-apk/ente-auth.apk
env:
SIGNING_KEY_PATH: '/home/runner/work/_temp/keystore/ente_auth_key.jks'
SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }}
SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }}
SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_STORE_PASSWORD }}
# Build Play store aab.
- name: Build
run: flutter build appbundle --release --flavor playstore
env:
SIGNING_KEY_PATH: "/home/runner/work/_temp/keystore/ente_auth_key.jks"
SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }}
SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }}
SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_STORE_PASSWORD }}
- name: Checksum
run: sha256sum build/app/outputs/flutter-apk/ente-auth.apk > build/app/outputs/flutter-apk/sha256sum
- name: Checksum
run: sha256sum build/app/outputs/flutter-apk/ente-auth.apk > build/app/outputs/flutter-apk/sha256sum
# Upload generated apk to the artifacts.
- uses: actions/upload-artifact@v2
with:
name: release-apk
path: build/app/outputs/flutter-apk/ente-auth.apk
# Upload generated apk to the artifacts.
- uses: actions/upload-artifact@v2
with:
name: release-apk
path: build/app/outputs/flutter-apk/ente-auth.apk
- uses: actions/upload-artifact@v2
with:
name: release-checksum
path: build/app/outputs/flutter-apk/sha256sum
- uses: actions/upload-artifact@v2
with:
name: release-checksum
path: build/app/outputs/flutter-apk/sha256sum
# Create a Github release
- uses: ncipollo/release-action@v1
with:
artifacts: "build/app/outputs/flutter-apk/ente-auth.apk,build/app/outputs/flutter-apk/sha256sum"
token: ${{ secrets.GITHUB_TOKEN }}
# Create a Github release
- uses: ncipollo/release-action@v1
with:
artifacts: "build/app/outputs/flutter-apk/ente-auth.apk,build/app/outputs/flutter-apk/sha256sum"
token: ${{ secrets.GITHUB_TOKEN }}
# Upload to Play store
- uses: ente-io/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{ secrets.SERVICE_ACCOUNT_JSON }}
packageName: io.ente.auth
releaseFiles: build/app/outputs/bundle/playstoreRelease/app-playstore-release.aab
track: internal

38
.github/workflows/cla.yaml vendored Normal file
View File

@@ -0,0 +1,38 @@
name: "CLA Assistant"
on:
issue_comment:
types: [created]
pull_request_target:
types: [opened, closed, synchronize]
jobs:
CLAAssistant:
# This job only runs for pull request comments
if: ${{ github.event.issue.pull_request }}
runs-on: ubuntu-latest
steps:
- name: "CLA Assistant"
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
# Beta Release
uses: contributor-assistant/github-action@v2.2.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# the below token should have repo scope and must be manually added by you in the repository's secret
PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
with:
path-to-signatures: "signatures/version1/cla.json"
path-to-document: "https://github.com/ente-io/cla/blob/main/CLA.md" # e.g. a CLA or a DCO document
# branch should not be protected
branch: "main"
allowlist: enteio
# the followings are the optional inputs - If the optional inputs are not given, then default values will be taken
#remote-organization-name: enter the remote organization name where the signatures should be stored (Default is storing the signatures in the same repository)
remote-repository-name: cla
#create-file-commit-message: 'For example: Creating file for storing CLA Signatures'
#signed-commit-message: 'For example: $contributorName has signed the CLA in #$pullRequestNo'
#custom-notsigned-prcomment: 'pull request comment with Introductory message to ask new contributors to sign'
#custom-pr-sign-comment: 'The signature to be committed in order to sign the CLA'
#custom-allsigned-prcomment: 'pull request comment when all contributors has signed, defaults to **CLA Assistant Lite bot** All Contributors have signed the CLA.'
#lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true)
#use-dco-flag: true - If you are using DCO instead of CLA

98
CLA.md Normal file
View File

@@ -0,0 +1,98 @@
## Contributor License Agreement
Thank you for your contribution to ente projects.
This contributor license agreement documents the rights granted by contributors
to Ente Technologies, Inc ("ente"). This license is for your protection as a
Contributor as well as the protection of ente, its users, and its licensees; you
may still license your own Contributions under other terms.
In exchange for the ability to participate in the ente community and for other
good consideration, the receipt of which is hereby acknowledged, you accept and
agree to the following terms and conditions for Your present and future
Contributions submitted to ente. Except for the license granted herein to ente
and recipients of software distributed by ente, You reserve all right, title,
and interest in and to Your Contributions.
1. Definitions.
"You" (or "Your") shall mean the copyright owner or legal entity authorized
by the copyright owner that is making this Agreement with ente. For legal
entities, the entity making a Contribution and all other entities that
control, are controlled by, or are under common control with that entity are
considered to be a single Contributor. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the direction or
management of such entity, whether by contract or otherwise, or (ii)
ownership of fifty percent (50%) or more of the outstanding shares, or (iii)
beneficial ownership of such entity.
"Contribution" shall mean any original work of authorship or invention,
including any modifications or additions to an existing work, that is
intentionally submitted by You to ente for inclusion in, or documentation of,
any of the products owned or managed by ente (the "Work"). For the purposes
of this definition, "submitted" means any form of electronic, verbal, or
written communication sent to ente or its representatives, including but not
limited to communication on electronic mailing lists, source code control
systems, and issue tracking systems that are managed by, or on behalf of,
ente for the purpose of discussing and improving the Work, but excluding
communication that is conspicuously marked or otherwise designated in writing
by You as "Not a Contribution."
2. Grant of Copyright License. Subject to the terms and conditions of this
Agreement, You hereby grant to ente and to recipients of software distributed
by ente a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare derivative works of,
publicly display, publicly perform, and distribute Your Contributions and
such derivative works.
3. Grant of Patent License. Subject to the terms and conditions of this
Agreement, You hereby grant to ente and to recipients of software distributed
by ente a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable by You that
are necessarily infringed by Your Contribution(s) alone or by combination of
Your Contribution(s) with the Work to which such Contribution(s) was
submitted. If any entity institutes patent litigation against You or any
other entity (including a cross-claim or counterclaim in a lawsuit) alleging
that your Contribution, or the Work to which you have contributed,
constitutes direct or contributory patent infringement, then any patent
licenses granted to that entity under this Agreement for that Contribution or
Work shall terminate as of the date such litigation is filed.
4. You represent that you are legally entitled to grant the above license. If
your employer(s) has rights to intellectual property that you create that
includes your Contributions, you represent that you have received permission
to make Contributions on behalf of that employer, that your employer has
waived such rights for your contributions to ente, or that your employer has
executed with ente a separate contributor license agreement substantially
similar to this Agreement. If You are a current employee or contractor of
ente, then the terms of your existing Employment Agreement or Consulting
Services Agreement shall supersede this CLA, and remain in full effect.
5. You represent that each of Your Contributions is Your original creation (see
section 7 for submissions on behalf of others). You represent that Your
Contribution submissions include complete details of any third-party license
or other restriction (including, but not limited to, related patents and
trademarks) of which you are personally aware and which are associated with
any part of Your Contributions.
6. You are not expected to provide support for Your Contributions, except to the
extent You desire to provide support. You may provide support for free, for
a fee, or not at all. Unless required by applicable law or agreed to in
writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including,
without limitation, any warranties or conditions of title, non-infringement,
merchantability, or fitness for a particular purpose.
7. Should You wish to submit work that is not Your original creation, You may
submit it to ente separately from any Contribution, identifying the complete
details of its source and of any license or other restriction (including, but
not limited to, related patents, trademarks, and license agreements) of which
you are personally aware, and conspicuously marking the work as "Not a
Contribution". Third-party materials licensed pursuant to: [license name(s)
here]" (substituting the bracketed text with the appropriate license
name(s)).
8. You agree to notify ente of any facts or circumstances of which you become
aware that would make these representations inaccurate in any respect.

View File

@@ -3,6 +3,8 @@
ente's Authenticator app helps you generate and store 2 step verification (2FA)
tokens on your mobile devices.
[Download now](#-download)
![App Screenshots](./screenshots/screenshots.png)
## ✨ Features
@@ -45,23 +47,29 @@ file, that adheres to the above format.
### Android
This repository's [GitHub releases](https://github.com/ente-io/auth/releases/latest/download/ente-auth.apks) contains APKs, built straight from source. These builds keep themselves updated, without relying on third party stores.
This repository's [GitHub
releases](https://github.com/ente-io/auth/releases/latest/download/ente-auth.apk)
contains APKs, built straight from source. These builds keep themselves updated,
without relying on third party stores.
You can alternatively install the build from PlayStore.
<a href="https://play.google.com/store/apps/details?id=io.ente.auth">
<img width="197" alt="Get it on Google Play" src="https://ente.io/static/ed265c3abdcd3efa5e29f64b927bcb44/e230a/play-store-badge.webp">
<a href="https://play.google.com/store/apps/details?id=io.ente.auth"> <img
width="197" alt="Get it on Google Play"
src="https://ente.io/static/ed265c3abdcd3efa5e29f64b927bcb44/e230a/play-store-badge.webp">
</a>
### iOS
<a href="https://apps.apple.com/us/app/ente-authenticator/id6444121398">
<img width="197" alt="Download on AppStore" src="https://user-images.githubusercontent.com/1161789/154795157-c4468ff9-97fd-46f3-87fe-dca789d8733a.png">
<a href="https://apps.apple.com/us/app/ente-authenticator/id6444121398"> <img
width="197" alt="Download on AppStore"
src="https://user-images.githubusercontent.com/1161789/154795157-c4468ff9-97fd-46f3-87fe-dca789d8733a.png">
</a>
### Desktop
Support for desktop platforms (Linux, Mac and Windows) is a [work in progress](https://github.com/ente-io/auth/tree/desktop).
Support for desktop platforms (Linux, Mac and Windows) is a [work in
progress](https://github.com/ente-io/auth/tree/desktop).
Please ⭐ this repo to be notified of updates.
@@ -69,7 +77,7 @@ Please ⭐ this repo to be notified of updates.
## 🔩 Architecture
The architecture that powers end-to-end encrypted storage and sync of your
tokens has been documented [here](architecture/index.md).
tokens has been documented [here](architecture/README.md).
## 🧑‍💻 Building from source
@@ -80,16 +88,22 @@ tokens has been documented [here](architecture/index.md).
4. For Android, run `flutter build apk --release --flavor independent`
5. For iOS, run `flutter build ios`
For maintainers, there is [additional documentation](RELEASES.md) on
automatically publishing the main branch to App store, Play store and GitHub
releases.
## 🙋‍♂️ Support
If you need help, please reach out to support@ente.io, and a human will get in
touch with you.
On the other hand, if you wish to support us, please
If you have feature requests, please create a [GitHub issue](https://github.com/ente-io/auth/issues/).
If you wish to support us, please ⭐
[star](https://github.com/ente-io/auth/stargazers) this project.
## 💜 Community
- Follow us on [Twitter](https://twitter.com/enteio)
- Join us on [Discord](https://ente.io/discord)
- Follow us on [Twitter](https://twitter.com/enteio) / [Mastodon](https://mstdn.social/@ente)
- Join us on [Discord](https://ente.io/discord) / [Matrix](https://ente.io/matrix)

12
RELEASES.md Normal file
View File

@@ -0,0 +1,12 @@
# Releases
1. Create a PR to bump up the version number in `pubspec.yaml`.
2. Once that is merged, tag main. This'll trigger the
[workflow](.github/workflows/ci.yml) to (a) create a new GitHub release with
the independently distributed APK, and (b) build and upload a release to
Google Play.
3. Xcode Cloud has already been configured and will automatically build and
release to TestFlight when step 1 was merged to main (you can see logs under
the PR checks).

View File

@@ -72,6 +72,9 @@ android {
playstore {
dimension "default"
}
fdroid {
dimension "default"
}
}
buildTypes {

View File

@@ -8,7 +8,7 @@ specifications of the underlying cryptography.
Your data is end-to-end encrypted with **ente**. Meaning, they are encrypted
with your `keys` before they leave your device.
<img src="e2ee.svg" class="architecture-svg" style="max-width: 600px"
<img src="assets/e2ee.svg" class="architecture-svg" style="max-width: 600px"
title="End-to-end encryption in ente" />
<br/>
@@ -39,7 +39,7 @@ leaves your device.
During registration, your `masterKey` is encrypted with your`keyEncryptionKey`,
and the resultant `encryptedMasterKey` is then sent to our servers for storage.
<img src="key-derivation.svg" class="architecture-svg" title="Key derivation" />
<img src="assets/key-derivation.svg" class="architecture-svg" title="Key derivation" />
#### <a id="key-encryption-flows-secondary-device"></a> Secondary Device
@@ -92,7 +92,7 @@ leave your device unencrypted.
- All of the above mentioned encrypted data is then pushed to the server for
storage.
<img src="token-encryption.svg" class="architecture-svg" title="Token
<img src="assets/token-encryption.svg" class="architecture-svg" title="Token
encryption" />
#### Download
@@ -149,7 +149,7 @@ the server (as discussed in [Key Encryption](#key-encryption), and decrypts it
with the entered `recoveryKey`. If the decryption succeeds, the client will know
that you have entered the correct `recoveryKey`.
<img src="recovery.svg" class="architecture-svg" title="Recovery" />
<img src="assets/recovery.svg" class="architecture-svg" title="Recovery" />
Now that you have your `masterKey`, the client will prompt you to set a new
password, using which it will derive a new `keyEncryptionKey`. This is then used
@@ -204,12 +204,12 @@ your `publicKey`. This `encryptedAuthToken` can only be decrypted with your
- This decrypted `authToken` can then from there on be used to authenticate all
API calls against our servers.
<img src="authentication.svg" class="architecture-svg" title="Authentication" />
<img src="assets/authentication.svg" class="architecture-svg" title="Authentication" />
### Security
Only by verifying access to your email and knowing your password can you obtain
an`authToken` that can be used to authenticate yourself against our servers.
an `authToken` that can be used to authenticate yourself against our servers.
---

View File

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 119 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 76 KiB

View File

Before

Width:  |  Height:  |  Size: 130 KiB

After

Width:  |  Height:  |  Size: 130 KiB

View File

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 101 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 105 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 123 KiB

View File

@@ -0,0 +1 @@
- Hello, FDroid!

View File

@@ -0,0 +1,35 @@
ente authenticator provides end-to-end encrypted cloud backups so that you don't have to worry about losing your tokens. We use the same protocols [ente
Photos](https://ente.io) uses to encrypt and preserve your data.
Multi Device Synchronization
ente will automatically sync the 2FA tokens you add to your account, across all
your devices. Every new device you sign into will have access to these tokens.
Mode
ente generates 2FA tokens offline, so your network connectivity will not get in
the way of your workflow.
Import and Export Tokens
You can add tokens to ente by one of the following methods:
1. Scanning a QR code
2. Manually entering (copy-pasting) a 2FA secret
3. Bulk importing from a file that contains a list of codes in the following
format:
```
otpauth://totp/ACCOUNT?secret=SUPERSECRET&issuer=SERVICE
```
The codes maybe separated by new lines or commas.
You can also export the codes you have added to ente, to an **unencrypted** text
file, that adheres to the above format.
SUPPORT
We take pride in offering human support. If you are our paid customer, you can reach out to team@ente.io and expect a response from our team within 24 hours.

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@@ -0,0 +1 @@
ente is an end-to-end encrypted authenticator app

View File

@@ -0,0 +1 @@
ente Authenticator

View File

@@ -0,0 +1,6 @@
flutter_icons:
android: "launcher_icon"
image_path: "assets/icon-light.png"
adaptive_icon_foreground: "assets/icon-light-adaptive-fg.png"
adaptive_icon_background: "#ffffff"

1
ios/.gitignore vendored
View File

@@ -8,6 +8,7 @@
.tags*
**/.vagrant/
**/DerivedData/
build/
Icon?
**/Pods/
**/.symlinks/

View File

@@ -54,7 +54,7 @@ PODS:
- Flutter
- flutter_native_splash (0.0.1):
- Flutter
- flutter_secure_storage (3.3.1):
- flutter_secure_storage (6.0.0):
- Flutter
- flutter_sodium (0.0.1):
- Flutter
@@ -69,31 +69,35 @@ PODS:
- move_to_background (0.0.1):
- Flutter
- MTBBarcodeScanner (5.0.11)
- open_filex (0.0.2):
- Flutter
- OrderedSet (5.0.0)
- package_info_plus (0.4.5):
- Flutter
- path_provider_ios (0.0.1):
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- qr_code_scanner (0.2.0):
- Flutter
- MTBBarcodeScanner
- Reachability (3.2)
- SDWebImage (5.13.4):
- SDWebImage/Core (= 5.13.4)
- SDWebImage/Core (5.13.4)
- Sentry/HybridSDK (7.30.2)
- SDWebImage (5.15.0):
- SDWebImage/Core (= 5.15.0)
- SDWebImage/Core (5.15.0)
- Sentry/HybridSDK (7.31.5)
- sentry_flutter (0.0.1):
- Flutter
- FlutterMacOS
- Sentry/HybridSDK (= 7.30.2)
- Sentry/HybridSDK (= 7.31.5)
- share_plus (0.0.1):
- Flutter
- shared_preferences_ios (0.0.1):
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- sqflite (0.0.2):
- Flutter
- FMDB (>= 2.7.5)
- SwiftyGif (5.4.3)
- SwiftyGif (5.4.4)
- Toast (4.0.0)
- url_launcher_ios (0.0.1):
- Flutter
@@ -113,12 +117,13 @@ DEPENDENCIES:
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
- local_auth (from `.symlinks/plugins/local_auth/ios`)
- move_to_background (from `.symlinks/plugins/move_to_background/ios`)
- open_filex (from `.symlinks/plugins/open_filex/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`)
- qr_code_scanner (from `.symlinks/plugins/qr_code_scanner/ios`)
- sentry_flutter (from `.symlinks/plugins/sentry_flutter/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
@@ -164,18 +169,20 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/local_auth/ios"
move_to_background:
:path: ".symlinks/plugins/move_to_background/ios"
open_filex:
:path: ".symlinks/plugins/open_filex/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_ios:
:path: ".symlinks/plugins/path_provider_ios/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/ios"
qr_code_scanner:
:path: ".symlinks/plugins/qr_code_scanner/ios"
sentry_flutter:
:path: ".symlinks/plugins/sentry_flutter/ios"
share_plus:
:path: ".symlinks/plugins/share_plus/ios"
shared_preferences_ios:
:path: ".symlinks/plugins/shared_preferences_ios/ios"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/ios"
sqflite:
:path: ".symlinks/plugins/sqflite/ios"
url_launcher_ios:
@@ -186,34 +193,35 @@ SPEC CHECKSUMS:
device_info: d7d233b645a32c40dfdc212de5cf646ca482f175
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
file_picker: 817ab1d8cd2da9d2da412a417162deee3500fc95
file_picker: ce3938a0df3cc1ef404671531facef740d03f920
fk_user_agent: 1f47ec39291e8372b1d692b50084b0d54103c545
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
flutter_email_sender: 02d7443217d8c41483223627972bfdc09f74276b
flutter_inappwebview: bfd58618f49dc62f2676de690fc6dcda1d6c3721
flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743
flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef
flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec
flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
flutter_sodium: c84426b4de738514b5b66cfdeb8a06634e72fe0b
fluttertoast: 74526702fea2c060ea55dde75895b7e1bde1c86b
fluttertoast: eb263d302cc92e04176c053d2385237e9f43fad0
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
local_auth: 1740f55d7af0a2e2a8684ce225fe79d8931e808c
move_to_background: 39a5b79b26d577b0372cbe8a8c55e7aa9fcd3a2d
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
open_filex: 6e26e659846ec990262224a12ef1c528bb4edbe4
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02
path_provider_foundation: 37748e03f12783f9de2cb2c4eadfaa25fe6d4852
qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
SDWebImage: e5cc87bf736e60f49592f307bdf9e157189298a3
Sentry: 9be48e341494bc976c963b05aa4a8ca48308c684
sentry_flutter: 544e6376e35b00eef9f0864f8bb7f10a0e204993
SDWebImage: 9bec4c5cdd9579e1f57104735ee0c37df274d593
Sentry: 4c9babff9034785067c896fd580b1f7de44da020
sentry_flutter: b10ae7a5ddcbc7f04648eeb2672b5747230172f1
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad
shared_preferences_foundation: 297b3ebca31b34ec92be11acd7fb0ba932c822ca
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780
SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de
url_launcher_ios: ae1517e5e344f5544fb090b079e11f399dfbe4d2
PODFILE CHECKSUM: b4e3a7eabb03395b66e81fc061789f61526ee6bb

View File

@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 51;
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
@@ -220,6 +220,7 @@
};
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
@@ -256,7 +257,7 @@
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
buildActionMask = 8;
files = (
);
inputPaths = (
@@ -264,9 +265,9 @@
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
runOnlyForDeploymentPostprocessing = 1;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n";
};
/* End PBXShellScriptBuildPhase section */

View File

@@ -31,6 +31,8 @@
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>MinimumOSVersion</key>
<string>12.0</string>
<key>NSCameraUsageDescription</key>

24
ios/ci_scripts/ci_post_clone.sh Executable file
View File

@@ -0,0 +1,24 @@
#!/bin/sh
# by default, the execution directory of this script is the ci_scripts directory
# CI_WORKSPACE is the directory of your cloned repo
echo "🟩 Navigate from ($PWD) to ($CI_WORKSPACE)"
cd $CI_WORKSPACE
echo "🟩 Install Flutter"
time git clone https://github.com/flutter/flutter.git -b stable $HOME/flutter
export PATH="$PATH:$HOME/flutter/bin"
echo "🟩 Flutter Precache"
time flutter precache --ios
echo "🟩 Install Flutter Dependencies"
time flutter pub get
echo "🟩 Install CocoaPods via Homebrew"
time HOMEBREW_NO_AUTO_UPDATE=1 brew install cocoapods
echo "🟩 Install CocoaPods dependencies..."
time cd ios && pod install
exit 0

View File

@@ -27,6 +27,9 @@ class App extends StatefulWidget {
class _AppState extends State<App> {
StreamSubscription<SignedOutEvent> _signedOutEvent;
StreamSubscription<SignedInEvent> _signedInEvent;
static const List<Locale> supportedLocales = <Locale>[
Locale('en'),
];
@override
void initState() {
@@ -78,13 +81,17 @@ class _AppState extends State<App> {
theme: lightTheme,
darkTheme: dartTheme,
debugShowCheckedModeBanner: false,
supportedLocales: AppLocalizations.supportedLocales,
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: supportedLocales,
localeListResolutionCallback: (locales, supportedLocales) {
for (Locale locale in locales) {
if (supportedLocales.contains(locale)) {
return locale;
}
}
// if device language is not supported by the app, use en as default
return const Locale('en');
},
localizationsDelegates: AppLocalizations.localizationsDelegates,
routes: _getRoutes,
),
);
@@ -95,7 +102,16 @@ class _AppState extends State<App> {
theme: lightThemeData,
darkTheme: darkThemeData,
debugShowCheckedModeBanner: false,
supportedLocales: AppLocalizations.supportedLocales,
supportedLocales: supportedLocales,
localeListResolutionCallback: (locales, supportedLocales) {
for (Locale locale in locales) {
if (supportedLocales.contains(locale)) {
return locale;
}
}
// if device language is not supported by the app, use en as default
return const Locale('en');
},
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,

View File

@@ -31,7 +31,6 @@ class Configuration {
static const emailKey = "email";
static const keyAttributesKey = "key_attributes";
static const keyKey = "key";
static const keyShouldHideFromRecents = "should_hide_from_recents";
static const keyShouldShowLockScreen = "should_show_lock_screen";
static const lastTempFolderClearTimeKey = "last_temp_folder_clear_time";
static const secretKeyKey = "secret_key";
@@ -453,14 +452,6 @@ class Configuration {
return _preferences.setBool(keyShouldShowLockScreen, value);
}
bool shouldHideFromRecents() {
return _preferences.getBool(keyShouldHideFromRecents) ?? false;
}
Future<void> setShouldHideFromRecents(bool value) {
return _preferences.setBool(keyShouldHideFromRecents, value);
}
void setVolatilePassword(String volatilePassword) {
_volatilePassword = volatilePassword;
}

116
lib/l10n/arb/app_de.arb Normal file
View File

@@ -0,0 +1,116 @@
{
"@@locale": "de",
"counterAppBarTitle": "Zähler",
"@counterAppBarTitle": {
"description": "Text, der in der AppBar der Zähler-Seite angezeigt wird"
},
"onBoardingBody": "Sichern Sie Ihre 2FA-Codes",
"onBoardingGetStarted": "Los geht's",
"setupFirstAccount": "Ihr erstes Konto einrichten",
"importScanQrCode": "Scannen eines QR-Codes",
"importEnterSetupKey": "Einen Setup-Schlüssel eingeben",
"importAccountPageTitle": "Kontodaten eingeben",
"codeIssuerHint": "Aussteller",
"codeSecretKeyHint" : "Geheimer Schlüssel",
"codeAccountHint": "Konto (you@domain.com)",
"accountKeyType": "Art des Schlüssels",
"timeBasedKeyType": "Zeitbasiert (TOTP)",
"counterBasedKeyType": "Zählerbasiert (HOTP)",
"saveAction": "Speichern",
"nextTotpTitle": "Weiter",
"deleteCodeTitle": "Code löschen?",
"deleteCodeMessage": "Sind Sie sicher, dass Sie diesen Code löschen wollen? Diese Aktion ist unumkehrbar.",
"viewLogsAction": "Protokolle anzeigen",
"sendLogsDescription": "Dadurch werden Protokolle übermittelt, die uns bei der Behebung Ihres Problems helfen. Obwohl wir Vorkehrungen treffen, um sicherzustellen, dass keine sensiblen Informationen protokolliert werden, empfehlen wir Ihnen, diese Protokolle anzusehen, bevor Sie sie weitergeben.",
"preparingLogsTitle": "Vorbereiten der Protokolle...",
"emailLogsTitle": "Protokolle versenden",
"emailLogsMessage": "Bitte senden Sie die Protokolle an {email}",
"@emailLogsMessage": {
"placeholders": {
"email": {
"type": "String"
}
}
},
"copyEmailAction": "E-Mail kopieren",
"exportLogsAction": "Protokolle exportieren",
"reportABug": "Fehlermelden",
"crashAndErrorReporting": "Absturz- und Fehlerberichte",
"reportBug": "Fehlermelden",
"emailUsMessage": "Bitte senden Sie uns eine E-Mail an {email}",
"@emailUsMessage": {
"placeholders": {
"email": {
"type": "String"
}
}
},
"contactSupport": "Support kontaktieren",
"verifyPassword": "Passwort überprüfen",
"pleaseWaitTitle": "Bitte warten...",
"generatingEncryptionKeysTitle": "Generierung von Verschlüsselungsschlüsseln...",
"recreatePassword": "Passwort wiederherstellen",
"recreatePasswordMessage": "Das aktuelle Gerät ist nicht leistungsfähig genug, um Ihr Passwort zu verifizieren, daher müssen wir es einmalig auf eine Weise neu generieren, die mit allen Geräten funktioniert. \n\nBitte melden Sie sich mit Ihrem Wiederherstellungsschlüssel an und generieren Sie Ihr Passwort neu (Sie können dasselbe erneut verwenden, wenn Sie möchten).",
"useRecoveryKeyAction": "Wiederherstellungsschlüssel verwenden",
"incorrectPassword": "Falsches Passwort",
"welcomeBackTitle": "Willkommen zurück!",
"madeWithLoveAtPrefix": "gemacht mit ❤️ bei ",
"changeEmail": "E-Mail ändern",
"ok": "OK",
"cancel": "Abbrechen",
"yes": "Ja",
"no": "Nein",
"email": "E-Mail",
"support": "Support",
"settings": "Einstellungen",
"copied": "Kopiert",
"tryAgainMessage": "Bitte versuchen Sie es erneut",
"existingUser": "Bestehender Benutzer",
"newUser" : "Neu bei ente",
"delete": "Löschen",
"enterYourPasswordHint": "Geben Sie Ihr Passwort ein",
"forgotPassword": "Passwort vergessen",
"oops": "Oops",
"somethingWentWrongMessage": "Ein Fehler ist aufgetreten, bitte versuchen Sie es erneut",
"leaveFamily": "Familie verlassen",
"leaveFamilyMessage": "Sind Sie sicher, dass Sie den Familien-Plan verlassen wollen?",
"inFamilyPlanMessage": "Sie haben einen Familien-Plan!",
"swipeHint": "Wischen Sie nach links, um Codes zu bearbeiten oder zu entfernen",
"scan": "Scannen",
"scanACode": "Scannen eines Codes",
"verify": "Überprüfen Sie",
"enterCodeHint": "Geben Sie den 6-stelligen Code \naus Ihrer Authentifikator-App ein.",
"lostDeviceTitle": "Gerät verloren?",
"twoFactorAuthTitle": "Zwei-Faktor-Authentifizierung",
"recoverAccount": "Konto wiederherstellen",
"enterRecoveryKeyHint": "Geben Sie Ihren Wiederherstellungsschlüssel ein",
"recover": "Wiederherstellen",
"contactSupportViaEmailMessage":"Bitte senden Sie eine E-Mail an {email} von Ihrer registrierten E-Mail-Adresse",
"@contactSupportViaEmailMessage": {
"placeholders": {
"email": {
"type": "String"
}
}
},
"noRecoveryKeyTitle": "Kein Wiederherstellungsschlüssel?",
"enterEmailHint": "Geben Sie Ihre E-Mail Adresse ein",
"invalidEmailTitle": "Ungültige E-Mail Adresse",
"invalidEmailMessage": "Bitte geben Sie eine gültige E-Mail Adresse ein.",
"deleteAccount": "Konto löschen",
"deleteAccountQuery": "Es wird uns leid tun, Sie gehen zu sehen. Haben Sie ein Problem?",
"yesSendFeedbackAction": "Ja, Feedback senden",
"noDeleteAccountAction": "Nein, Konto löschen",
"initiateAccountDeleteTitle": "Bitte authentifizieren Sie sich, um die Kontolöschung einzuleiten",
"confirmAccountDeleteTitle": "Sind Sie sicher, dass Sie Ihr ente Konto löschen wollen?",
"confirmAccountDeleteMessage": "Ihre hochgeladenen Daten werden in allen Anwendungen (sowohl Fotos als auch Authenticator) zur Löschung vorgesehen und Ihr Konto wird dauerhaft gelöscht.",
"sendEmail": "E-Mail senden",
"createNewAccount": "Neues Konto erstellen",
"passwordStrengthWeak": "Schwach",
"passwordStrengthStrong": "Stark",
"passwordStrengthModerate": "Mittel",
"confirmPassword": "Bestätigen Sie das Passwort",
"close": "Schließen",
"oopsSomethingWentWrong": "Ups, da ist etwas schief gelaufen."
}

View File

@@ -6,7 +6,6 @@
},
"onBoardingBody": "Secure your 2FA codes",
"onBoardingGetStarted": "Get Started",
"setupFirstAccount": "Setup your first account",
"importScanQrCode": "Scan a QR Code",
"importEnterSetupKey": "Enter a setup key",
@@ -18,7 +17,100 @@
"timeBasedKeyType": "Time based (TOTP)",
"counterBasedKeyType": "Counter based (HOTP)",
"saveAction": "Save",
"nextTotpTitle": "next",
"deleteCodeTitle": "Delete code?",
"deleteCodeMessage": "Are you sure you want to delete this code? This action is irreversible.",
"viewLogsAction": "View logs",
"sendLogsDescription": "This will send across logs to help us debug your issue. While we take precautions to ensure that sensitive information is not logged, we encourage you to view these logs before sharing them.",
"preparingLogsTitle": "Preparing logs...",
"emailLogsTitle": "Email logs",
"emailLogsMessage": "Please send the logs to {email}",
"@emailLogsMessage": {
"placeholders": {
"email": {
"type": "String"
}
}
},
"copyEmailAction": "Copy email",
"exportLogsAction": "Export logs",
"reportABug": "Report a bug",
"crashAndErrorReporting": "Crash & error reporting",
"reportBug": "Report bug",
"emailUsMessage": "Please email us at {email}",
"@emailUsMessage": {
"placeholders": {
"email": {
"type": "String"
}
}
},
"contactSupport": "Contact support",
"verifyPassword": "Verify password",
"pleaseWaitTitle": "Please wait...",
"generatingEncryptionKeysTitle": "Generating encryption keys...",
"recreatePassword": "Recreate password",
"recreatePasswordMessage": "The current device is not powerful enough to verify your password, so we need to regenerate it once in a way that works with all devices. \n\nPlease login using your recovery key and regenerate your password (you can use the same one again if you wish).",
"useRecoveryKeyAction": "Use recovery key",
"incorrectPassword": "Incorrect password",
"welcomeBackTitle": "Welcome back!",
"madeWithLoveAtPrefix": "made with ❤️ at ",
"changeEmail": "change email",
"ok": "OK",
"cancel": "Cancel",
"yes": "Yes",
"no": "No",
"email": "Email",
"support": "Support",
"settings": "Settings",
"copied": "Copied",
"tryAgainMessage": "Please try again",
"existingUser": "Existing User",
"newUser" : "New to ente"
}
"newUser" : "New to ente",
"delete": "Delete",
"enterYourPasswordHint": "Enter your password",
"forgotPassword": "Forgot password",
"oops": "Oops",
"somethingWentWrongMessage": "Something went wrong, please try again",
"leaveFamily": "Leave family",
"leaveFamilyMessage": "Are you sure that you want to leave the family plan?",
"inFamilyPlanMessage": "You are on a family plan!",
"swipeHint": "Swipe left to edit or remove codes",
"scan": "Scan",
"scanACode": "Scan a code",
"verify": "Verify",
"enterCodeHint": "Enter the 6-digit code from\nyour authenticator app",
"lostDeviceTitle": "Lost device?",
"twoFactorAuthTitle": "Two-factor authentication",
"recoverAccount": "Recover account",
"enterRecoveryKeyHint": "Enter your recovery key",
"recover": "Recover",
"contactSupportViaEmailMessage":"Please drop an email to {email} from your registered email address",
"@contactSupportViaEmailMessage": {
"placeholders": {
"email": {
"type": "String"
}
}
},
"noRecoveryKeyTitle": "No recovery key?",
"enterEmailHint": "Enter your email address",
"invalidEmailTitle": "Invalid email address",
"invalidEmailMessage": "Please enter a valid email address.",
"deleteAccount": "Delete account",
"deleteAccountQuery": "We'll be sorry to see you go. Are you facing some issue?",
"yesSendFeedbackAction": "Yes, send feedback",
"noDeleteAccountAction": "No, delete account",
"initiateAccountDeleteTitle": "Please authenticate to initiate account deletion",
"confirmAccountDeleteTitle": "Are you sure you want to delete your ente account?",
"confirmAccountDeleteMessage": "Your uploaded data, across all apps (Photos and Authenticator both), will be scheduled for deletion, and your account will be permanently deleted.",
"sendEmail": "Send email",
"createNewAccount": "Create new account",
"passwordStrengthWeak": "Weak",
"passwordStrengthStrong": "Strong",
"passwordStrengthModerate": "Moderate",
"confirmPassword": "Confirm password",
"close": "Close",
"oopsSomethingWentWrong": "Oops, Something went wrong."
}

View File

@@ -7,6 +7,7 @@ import 'package:ente_auth/core/constants.dart';
import 'package:ente_auth/core/event_bus.dart';
import 'package:ente_auth/core/network.dart';
import 'package:ente_auth/events/user_details_changed_event.dart';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/models/delete_account.dart';
import 'package:ente_auth/models/key_attributes.dart';
import 'package:ente_auth/models/key_gen_result.dart';
@@ -47,7 +48,8 @@ class UserService {
bool isChangeEmail = false,
bool isCreateAccountScreen = false,
}) async {
final dialog = createProgressDialog(context, "Please wait...");
final l10n = context.l10n;
final dialog = createProgressDialog(context, l10n.pleaseWaitTitle);
await dialog.show();
try {
final response = await _dio.post(
@@ -191,7 +193,8 @@ class UserService {
Future<DeleteChallengeResponse> getDeleteChallenge(
BuildContext context,
) async {
final dialog = createProgressDialog(context, "Please wait...");
final l10n = context.l10n;
final dialog = createProgressDialog(context, l10n.pleaseWaitTitle);
await dialog.show();
try {
final response = await _dio.get(
@@ -259,7 +262,8 @@ class UserService {
}
Future<void> verifyEmail(BuildContext context, String ott) async {
final dialog = createProgressDialog(context, "Please wait...");
final l10n = context.l10n;
final dialog = createProgressDialog(context, l10n.pleaseWaitTitle);
await dialog.show();
try {
final response = await _dio.post(
@@ -329,7 +333,8 @@ class UserService {
String email,
String ott,
) async {
final dialog = createProgressDialog(context, "Please wait...");
final l10n = context.l10n;
final dialog = createProgressDialog(context, l10n.pleaseWaitTitle);
await dialog.show();
try {
final response = await _dio.post(
@@ -498,7 +503,8 @@ class UserService {
}
Future<void> recoverTwoFactor(BuildContext context, String sessionID) async {
final dialog = createProgressDialog(context, "Please wait...");
final l10n = context.l10n;
final dialog = createProgressDialog(context, l10n.pleaseWaitTitle);
await dialog.show();
try {
final response = await _dio.get(
@@ -618,7 +624,8 @@ class UserService {
String encryptedSecret,
String secretDecryptionNonce,
) async {
final dialog = createProgressDialog(context, "Please wait...");
final l10n = context.l10n;
final dialog = createProgressDialog(context, l10n.pleaseWaitTitle);
await dialog.show();
String secret;
try {

View File

@@ -1,5 +1,6 @@
// @dart=2.9
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/services/user_service.dart';
import 'package:ente_auth/utils/dialog_util.dart';
import 'package:ente_auth/utils/email_util.dart';
@@ -17,20 +18,21 @@ class _ChangeEmailDialogState extends State<ChangeEmailDialog> {
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return AlertDialog(
title: const Text("Enter your email address"),
title: Text(l10n.enterEmailHint),
content: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
decoration: const InputDecoration(
hintText: 'Email',
hintStyle: TextStyle(
decoration: InputDecoration(
hintText: l10n.email,
hintStyle: const TextStyle(
color: Colors.white30,
),
contentPadding: EdgeInsets.all(12),
contentPadding: const EdgeInsets.all(12),
),
onChanged: (value) {
setState(() {
@@ -47,9 +49,9 @@ class _ChangeEmailDialogState extends State<ChangeEmailDialog> {
),
actions: [
TextButton(
child: const Text(
"Cancel",
style: TextStyle(
child: Text(
l10n.cancel,
style: const TextStyle(
color: Colors.redAccent,
),
),
@@ -58,9 +60,9 @@ class _ChangeEmailDialogState extends State<ChangeEmailDialog> {
},
),
TextButton(
child: const Text(
"Verify",
style: TextStyle(
child: Text(
l10n.verify,
style: const TextStyle(
color: Colors.purple,
),
),
@@ -68,8 +70,8 @@ class _ChangeEmailDialogState extends State<ChangeEmailDialog> {
if (!isValidEmail(_email)) {
showErrorDialog(
context,
"Invalid email address",
"Please enter a valid email address.",
l10n.invalidEmailTitle,
l10n.invalidEmailMessage,
);
return;
}

View File

@@ -3,6 +3,7 @@
import 'dart:convert';
import 'package:ente_auth/core/configuration.dart';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/models/delete_account.dart';
import 'package:ente_auth/services/local_authentication_service.dart';
import 'package:ente_auth/services/user_service.dart';
@@ -20,10 +21,11 @@ class DeleteAccountPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return Scaffold(
appBar: AppBar(
elevation: 0,
title: const Text("Delete account"),
title: Text(l10n.deleteAccount),
leading: IconButton(
icon: const Icon(Icons.arrow_back),
color: Theme.of(context).iconTheme.color,
@@ -47,7 +49,7 @@ class DeleteAccountPage extends StatelessWidget {
),
Center(
child: Text(
"We'll be sorry to see you go. Are you facing some issue?",
l10n.deleteAccountQuery,
style: Theme.of(context).textTheme.subtitle1,
),
),
@@ -74,7 +76,7 @@ class DeleteAccountPage extends StatelessWidget {
height: 24,
),
GradientButton(
text: "Yes, send feedback",
text: l10n.yesSendFeedbackAction,
iconData: Icons.check,
onTap: () async {
await sendEmail(
@@ -104,9 +106,9 @@ class DeleteAccountPage extends StatelessWidget {
),
backgroundColor: Colors.white,
),
label: const Text(
"No, delete account",
style: TextStyle(
label: Text(
l10n.noDeleteAccountAction,
style: const TextStyle(
color: Colors.redAccent, // same for both themes
),
textAlign: TextAlign.center,
@@ -143,21 +145,20 @@ class DeleteAccountPage extends StatelessWidget {
BuildContext context,
DeleteChallengeResponse response,
) async {
final l10n = context.l10n;
final hasAuthenticated =
await LocalAuthenticationService.instance.requestLocalAuthentication(
context,
"Please authenticate to initiate account deletion",
l10n.initiateAccountDeleteTitle,
);
if (hasAuthenticated) {
final choice = await showChoiceDialog(
context,
'Are you sure you want to delete your ente account?',
'Your uploaded data, across all apps '
'(Photos and Authenticator both), will be scheduled for deletion,'
'and your account will be permanently deleted.',
firstAction: 'Cancel',
secondAction: 'Delete',
l10n.confirmAccountDeleteTitle,
l10n.confirmAccountDeleteMessage,
firstAction: l10n.cancel,
secondAction: l10n.delete,
firstActionColor: Theme.of(context).colorScheme.onSurface,
secondActionColor: Colors.red,
);
@@ -175,10 +176,11 @@ class DeleteAccountPage extends StatelessWidget {
}
Future<void> _requestEmailForDeletion(BuildContext context) async {
final l10n = context.l10n;
final AlertDialog alert = AlertDialog(
title: const Text(
"Delete account",
style: TextStyle(
title: Text(
l10n.deleteAccount,
style: const TextStyle(
color: Colors.red,
),
),
@@ -208,9 +210,9 @@ class DeleteAccountPage extends StatelessWidget {
),
actions: [
TextButton(
child: const Text(
"Send email",
style: TextStyle(
child: Text(
l10n.sendEmail,
style: const TextStyle(
color: Colors.red,
),
),
@@ -225,7 +227,7 @@ class DeleteAccountPage extends StatelessWidget {
),
TextButton(
child: Text(
"Ok",
l10n.ok,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
),

View File

@@ -5,6 +5,7 @@ import 'dart:io';
import 'package:email_validator/email_validator.dart';
import 'package:ente_auth/core/configuration.dart';
import 'package:ente_auth/ente_theme_data.dart';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/models/billing_plan.dart';
import 'package:ente_auth/services/billing_service.dart';
import 'package:ente_auth/services/user_service.dart';
@@ -122,13 +123,14 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
}
Widget _getBody() {
var passwordStrengthText = 'Weak';
final l10n = context.l10n;
var passwordStrengthText = l10n.passwordStrengthWeak;
var passwordStrengthColor = Colors.redAccent;
if (_passwordStrength > kStrongPasswordStrengthThreshold) {
passwordStrengthText = 'Strong';
passwordStrengthText = l10n.passwordStrengthStrong;
passwordStrengthColor = Colors.greenAccent;
} else if (_passwordStrength > kMildPasswordStrengthThreshold) {
passwordStrengthText = 'Moderate';
passwordStrengthText = l10n.passwordStrengthModerate;
passwordStrengthColor = Colors.orangeAccent;
}
return Column(
@@ -141,7 +143,7 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
padding:
const EdgeInsets.symmetric(vertical: 30, horizontal: 20),
child: Text(
'Create new account',
l10n.createNewAccount,
style: Theme.of(context).textTheme.headline4,
),
),
@@ -153,7 +155,7 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
decoration: InputDecoration(
fillColor: _emailIsValid ? _validFieldValueColor : null,
filled: true,
hintText: 'Email',
hintText: l10n.email,
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 14,
@@ -268,7 +270,7 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
decoration: InputDecoration(
fillColor: _passwordsMatch ? _validFieldValueColor : null,
filled: true,
hintText: "Confirm password",
hintText: l10n.confirmPassword,
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 14,
@@ -510,13 +512,14 @@ class PricingWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return FutureBuilder<BillingPlans>(
future: BillingService.instance.getBillingPlans(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return _buildPlans(context, snapshot.data);
} else if (snapshot.hasError) {
return const Text("Oops, Something went wrong.");
return Text(l10n.oopsSomethingWentWrong);
}
return const EnteLoadingWidget();
},
@@ -524,6 +527,7 @@ class PricingWidget extends StatelessWidget {
}
Container _buildPlans(BuildContext context, BillingPlans plans) {
final l10n = context.l10n;
final planWidgets = <BillingPlanWidget>[];
for (final plan in plans.plans) {
final productID = Platform.isAndroid ? plan.androidID : plan.iosID;
@@ -564,16 +568,16 @@ class PricingWidget extends StatelessWidget {
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: const [
Icon(
children: [
const Icon(
Icons.close,
size: 12,
color: Colors.white38,
),
Padding(padding: EdgeInsets.all(1)),
const Padding(padding: EdgeInsets.all(1)),
Text(
"Close",
style: TextStyle(
l10n.close,
style: const TextStyle(
color: Colors.white38,
),
),

View File

@@ -1,6 +1,7 @@
// @dart=2.9
import 'package:ente_auth/core/configuration.dart';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/services/user_service.dart';
import 'package:ente_auth/ui/account/recovery_key_page.dart';
import 'package:ente_auth/ui/common/dynamic_fab.dart';
@@ -400,15 +401,16 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
}
Future<void> _showRecoveryCodeDialog(String password) async {
final l10n = context.l10n;
final dialog =
createProgressDialog(context, "Generating encryption keys...");
createProgressDialog(context, l10n.generatingEncryptionKeysTitle);
await dialog.show();
try {
final result = await Configuration.instance.generateKey(password);
Configuration.instance.setVolatilePassword(null);
await dialog.hide();
onDone() async {
final dialog = createProgressDialog(context, "Please wait...");
final dialog = createProgressDialog(context, l10n.pleaseWaitTitle);
await dialog.show();
try {
await UserService.instance.setAttributes(result);

View File

@@ -2,6 +2,7 @@
import 'package:ente_auth/core/configuration.dart';
import 'package:ente_auth/core/errors.dart';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/models/key_attributes.dart';
import 'package:ente_auth/ui/account/recovery_page.dart';
import 'package:ente_auth/ui/common/dialogs.dart';
@@ -40,6 +41,7 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
final isKeypadOpen = MediaQuery.of(context).viewInsets.bottom > 100;
FloatingActionButtonLocation fabLocation() {
@@ -66,10 +68,10 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
floatingActionButton: DynamicFAB(
isKeypadOpen: isKeypadOpen,
isFormValid: _passwordController.text.isNotEmpty,
buttonText: 'Verify password',
buttonText: l10n.verifyPassword,
onPressedFunction: () async {
FocusScope.of(context).unfocus();
final dialog = createProgressDialog(context, "Please wait...");
final dialog = createProgressDialog(context, l10n.pleaseWaitTitle);
await dialog.show();
try {
await Configuration.instance.decryptAndSaveSecrets(
@@ -81,14 +83,11 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
await dialog.hide();
final dialogUserChoice = await showChoiceDialog(
context,
"Recreate password",
"The current device is not powerful enough to verify your "
"password, so we need to regenerate it once in a way that "
"works with all devices. \n\nPlease login using your "
"recovery key and regenerate your password (you can use the same one again if you wish).",
firstAction: "Cancel",
l10n.recreatePassword,
l10n.recreatePasswordMessage,
firstAction: l10n.cancel,
firstActionColor: Theme.of(context).colorScheme.primary,
secondAction: "Use recovery key",
secondAction: l10n.useRecoveryKeyAction,
secondActionColor: Theme.of(context).colorScheme.primary,
);
if (dialogUserChoice == DialogUserChoice.secondChoice) {
@@ -107,17 +106,17 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
final dialogUserChoice = await showChoiceDialog(
context,
"Incorrect password",
"Please try again",
firstAction: "Contact Support",
l10n.incorrectPassword,
l10n.tryAgainMessage,
firstAction: l10n.contactSupport,
firstActionColor: Theme.of(context).colorScheme.primary,
secondAction: "Ok",
secondAction: l10n.ok,
secondActionColor: Theme.of(context).colorScheme.primary,
);
if (dialogUserChoice == DialogUserChoice.firstChoice) {
await sendLogs(
context,
"Contact support",
l10n.contactSupport,
"support@ente.io",
postShare: () {},
);
@@ -141,6 +140,7 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
}
Widget _getBody() {
final l10n = context.l10n;
return Column(
children: [
Expanded(
@@ -151,7 +151,7 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
padding:
const EdgeInsets.symmetric(vertical: 30, horizontal: 20),
child: Text(
'Welcome back!',
l10n.welcomeBackTitle,
style: Theme.of(context).textTheme.headline4,
),
),
@@ -174,7 +174,7 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
child: TextFormField(
autofillHints: const [AutofillHints.password],
decoration: InputDecoration(
hintText: "Enter your password",
hintText: l10n.enterYourPasswordHint,
filled: true,
contentPadding: const EdgeInsets.all(20),
border: UnderlineInputBorder(
@@ -236,7 +236,7 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
},
child: Center(
child: Text(
"Forgot password",
l10n.forgotPassword,
style:
Theme.of(context).textTheme.subtitle1.copyWith(
fontSize: 14,
@@ -248,8 +248,10 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () async {
final dialog =
createProgressDialog(context, "Please wait...");
final dialog = createProgressDialog(
context,
l10n.pleaseWaitTitle,
);
await dialog.show();
await Configuration.instance.logout();
await dialog.hide();
@@ -258,7 +260,7 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
},
child: Center(
child: Text(
"Change email",
l10n.changeEmail,
style:
Theme.of(context).textTheme.subtitle1.copyWith(
fontSize: 14,

View File

@@ -2,6 +2,7 @@
import 'package:ente_auth/core/configuration.dart';
import 'package:ente_auth/ente_theme_data.dart';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/models/sessions.dart';
import 'package:ente_auth/services/user_service.dart';
import 'package:ente_auth/ui/common/loading_widget.dart';
@@ -111,7 +112,8 @@ class _SessionsPageState extends State<SessionsPage> {
}
Future<void> _terminateSession(Session session) async {
final dialog = createProgressDialog(context, "Please wait...");
final l10n = context.l10n;
final dialog = createProgressDialog(context, l10n.pleaseWaitTitle);
await dialog.show();
try {
await UserService.instance.terminateSession(session.token);
@@ -122,8 +124,8 @@ class _SessionsPageState extends State<SessionsPage> {
_logger.severe('failed to terminate', e, s);
showErrorDialog(
context,
'Oops',
"Something went wrong, please try again",
l10n.oops,
l10n.somethingWentWrongMessage,
);
}
}

View File

@@ -2,6 +2,7 @@ import 'dart:async';
import 'package:clipboard/clipboard.dart';
import 'package:ente_auth/ente_theme_data.dart';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/models/code.dart';
import 'package:ente_auth/onboarding/view/setup_enter_secret_key_page.dart';
import 'package:ente_auth/store/code_store.dart';
@@ -49,6 +50,7 @@ class _CodeWidgetState extends State<CodeWidget> {
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return Container(
margin: const EdgeInsets.only(left: 16, right: 16, bottom: 8, top: 8),
child: Slidable(
@@ -174,7 +176,7 @@ class _CodeWidgetState extends State<CodeWidget> {
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
"next",
l10n.nextTotpTitle,
style: Theme.of(context).textTheme.caption,
),
Text(
@@ -224,20 +226,21 @@ class _CodeWidgetState extends State<CodeWidget> {
}
void _onDeletePressed(_) {
final l10n = context.l10n;
final AlertDialog alert = AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
title: Text(
"Delete code?",
l10n.deleteCodeTitle,
style: Theme.of(context).textTheme.headline6,
),
content: const Text(
"Are you sure you want to delete this code? This action is irreversible.",
content: Text(
l10n.deleteCodeMessage,
),
actions: [
TextButton(
child: const Text(
"Delete",
style: TextStyle(
child: Text(
l10n.delete,
style: const TextStyle(
color: Colors.red,
),
),

View File

@@ -12,6 +12,9 @@ class MenuItemWidget extends StatefulWidget {
final IconData? trailingIcon;
final Widget? trailingSwitch;
final bool trailingIconIsMuted;
/// If provided, add this much extra spacing to the right of the trailing icon.
final double trailingExtraMargin;
final VoidCallback? onTap;
final VoidCallback? onDoubleTap;
final Color? menuItemColor;
@@ -27,6 +30,7 @@ class MenuItemWidget extends StatefulWidget {
this.trailingIcon,
this.trailingSwitch,
this.trailingIconIsMuted = false,
this.trailingExtraMargin = 0.0,
this.onTap,
this.onDoubleTap,
this.menuItemColor,
@@ -141,11 +145,15 @@ class _MenuItemWidgetState extends State<MenuItemWidget> {
),
)
: widget.trailingIcon != null
? Icon(
widget.trailingIcon,
color: widget.trailingIconIsMuted
? enteColorScheme.strokeMuted
: null,
? Padding(
padding:
EdgeInsets.only(right: widget.trailingExtraMargin),
child: Icon(
widget.trailingIcon,
color: widget.trailingIconIsMuted
? enteColorScheme.strokeMuted
: null,
),
)
: widget.trailingSwitch ?? const SizedBox.shrink(),
],

View File

@@ -240,6 +240,7 @@ class _HomePageState extends State<HomePage> {
}
Widget _getCoachMarkWidget() {
final l10n = context.l10n;
return GestureDetector(
onTap: () async {
await PreferenceService.instance.setHasShownCoachMark(true);
@@ -268,7 +269,7 @@ class _HomePageState extends State<HomePage> {
height: 24,
),
Text(
"Swipe left to edit or remove codes",
l10n.swipeHint,
style: Theme.of(context).textTheme.headline6,
),
const SizedBox(
@@ -282,7 +283,7 @@ class _HomePageState extends State<HomePage> {
.setHasShownCoachMark(true);
setState(() {});
},
child: const Text("OK"),
child: Text(l10n.ok),
),
)
],

View File

@@ -1,6 +1,7 @@
// @dart=2.9
import 'package:ente_auth/ente_theme_data.dart';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/models/user_details.dart';
import 'package:ente_auth/services/user_service.dart';
import 'package:ente_auth/ui/common/dialogs.dart';
@@ -17,6 +18,7 @@ class ChildSubscriptionWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
final String familyAdmin = userDetails.familyData.members
.firstWhere((element) => element.isAdmin)
.email;
@@ -27,7 +29,7 @@ class ChildSubscriptionWidget extends StatelessWidget {
children: [
Center(
child: Text(
"You are on a family plan!",
l10n.inFamilyPlanMessage,
style: Theme.of(context).textTheme.bodyText1,
),
),
@@ -76,9 +78,9 @@ class ChildSubscriptionWidget extends StatelessWidget {
const EdgeInsets.symmetric(vertical: 18, horizontal: 100),
backgroundColor: Colors.red[500],
),
child: const Text(
"Leave Family",
style: TextStyle(
child: Text(
l10n.leaveFamily,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18,
color: Colors.white, // same for both themes
@@ -120,19 +122,20 @@ class ChildSubscriptionWidget extends StatelessWidget {
}
Future<void> _leaveFamilyPlan(BuildContext context) async {
final l10n = context.l10n;
final choice = await showChoiceDialog(
context,
'Leave family',
'Are you sure that you want to leave the family plan?',
firstAction: 'No',
secondAction: 'Yes',
l10n.leaveFamily,
l10n.leaveFamilyMessage,
firstAction: l10n.no,
secondAction: l10n.yes,
firstActionColor: Theme.of(context).colorScheme.alternativeColor,
secondActionColor: Theme.of(context).colorScheme.onSurface,
);
if (choice != DialogUserChoice.secondChoice) {
return;
}
final dialog = createProgressDialog(context, "Please wait...");
final dialog = createProgressDialog(context, l10n.pleaseWaitTitle);
await dialog.show();
try {
await UserService.instance.leaveFamilyPlan();

View File

@@ -3,6 +3,7 @@
import 'dart:io';
import 'package:ente_auth/ente_theme_data.dart';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/models/subscription.dart';
import 'package:ente_auth/services/billing_service.dart';
import 'package:ente_auth/services/user_service.dart';
@@ -49,7 +50,8 @@ class _PaymentWebPageState extends State<PaymentWebPage> {
@override
Widget build(BuildContext context) {
_dialog = createProgressDialog(context, "Please wait...");
final l10n = context.l10n;
_dialog = createProgressDialog(context, l10n.pleaseWaitTitle);
if (initPaymentUrl == null) {
return const EnteLoadingWidget();
}

View File

@@ -1,5 +1,6 @@
import 'dart:io';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/models/code.dart';
import 'package:flutter/material.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';
@@ -30,9 +31,10 @@ class ScannerPageState extends State<ScannerPage> {
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return Scaffold(
appBar: AppBar(
title: const Text("Scan"),
title: Text(l10n.scan),
),
body: Column(
children: <Widget>[
@@ -47,7 +49,7 @@ class ScannerPageState extends State<ScannerPage> {
Expanded(
flex: 1,
child: Center(
child: (totp != null) ? Text(totp!) : const Text('Scan a code'),
child: (totp != null) ? Text(totp!) : Text(l10n.scanACode),
),
)
],

View File

@@ -6,7 +6,7 @@ import 'package:ente_auth/ente_theme_data.dart';
import 'package:ente_auth/services/update_service.dart';
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
// import 'package:open_file/open_file.dart';
import 'package:open_filex/open_filex.dart';
class AppUpdateDialog extends StatefulWidget {
final LatestVersionInfo latestVersionInfo;
@@ -157,7 +157,7 @@ class _ApkDownloaderDialogState extends State<ApkDownloaderDialog> {
},
);
Navigator.of(context, rootNavigator: true).pop('dialog');
// OpenFile.open(_saveUrl);
OpenFilex.open(_saveUrl);
} catch (e) {
Logger("ApkDownloader").severe(e);
final AlertDialog alert = AlertDialog(

View File

@@ -6,6 +6,7 @@ import 'dart:ui';
import 'package:ente_auth/core/configuration.dart';
import 'package:ente_auth/ente_theme_data.dart';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/models/code.dart';
import 'package:ente_auth/services/authenticator_service.dart';
import 'package:ente_auth/services/local_authentication_service.dart';
@@ -215,11 +216,12 @@ class DataSectionWidget extends StatelessWidget {
}
Future<void> _pickImportFile(BuildContext context) async {
final l10n = context.l10n;
FilePickerResult result = await FilePicker.platform.pickFiles();
if (result == null) {
return;
}
final dialog = createProgressDialog(context, "Please wait...");
final dialog = createProgressDialog(context, l10n.pleaseWaitTitle);
await dialog.show();
try {
File file = File(result.files.single.path);
@@ -257,7 +259,7 @@ class DataSectionWidget extends StatelessWidget {
actions: [
TextButton(
child: Text(
"Okay",
l10n.ok,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
),

View File

@@ -1,6 +1,7 @@
// @dart=2.9
import 'package:ente_auth/core/configuration.dart';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/ui/settings/common_settings.dart';
import 'package:ente_auth/ui/settings/settings_section_title.dart';
import 'package:ente_auth/ui/settings/settings_text_item.dart';
@@ -12,6 +13,8 @@ class DebugSectionWidget extends StatelessWidget {
const DebugSectionWidget({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
// This is a debug only section not shown to end users, so these strings are
// not translated.
return ExpandablePanel(
header: const SettingsSectionTitle("Debug"),
collapsed: Container(),
@@ -38,6 +41,7 @@ class DebugSectionWidget extends StatelessWidget {
}
void _showKeyAttributesDialog(BuildContext context) {
final l10n = context.l10n;
final keyAttributes = Configuration.instance.getKeyAttributes();
final AlertDialog alert = AlertDialog(
title: const Text("key attributes"),
@@ -73,7 +77,7 @@ class DebugSectionWidget extends StatelessWidget {
),
actions: [
TextButton(
child: const Text("OK"),
child: Text(l10n.ok),
onPressed: () {
Navigator.of(context, rootNavigator: true).pop('dialog');
},

View File

@@ -1,3 +1,4 @@
import 'package:ente_auth/l10n/l10n.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
@@ -8,13 +9,14 @@ class MadeWithLoveWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return GestureDetector(
onTap: () {
launchUrl(Uri.parse("https://ente.io"));
},
child: RichText(
text: TextSpan(
text: "made with ❤️ at ",
text: l10n.madeWithLoveAtPrefix,
style: DefaultTextStyle.of(context).style,
children: const <TextSpan>[
TextSpan(

View File

@@ -1,9 +1,7 @@
// @dart=2.9
import 'dart:io';
import 'package:ente_auth/core/configuration.dart';
import 'package:ente_auth/ente_theme_data.dart';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/services/local_authentication_service.dart';
import 'package:ente_auth/theme/ente_theme.dart';
import 'package:ente_auth/ui/account/sessions_page.dart';
@@ -13,7 +11,6 @@ import 'package:ente_auth/ui/components/menu_item_widget.dart';
import 'package:ente_auth/ui/components/toggle_switch_widget.dart';
import 'package:ente_auth/ui/settings/common_settings.dart';
import 'package:flutter/material.dart';
import 'package:flutter_windowmanager/flutter_windowmanager.dart';
class SecuritySectionWidget extends StatefulWidget {
const SecuritySectionWidget({Key key}) : super(key: key);
@@ -45,6 +42,7 @@ class _SecuritySectionWidgetState extends State<SecuritySectionWidget> {
}
Widget _getSectionOptions(BuildContext context) {
final l10n = context.l10n;
final List<Widget> children = [];
children.addAll([
MenuItemWidget(
@@ -68,97 +66,6 @@ class _SecuritySectionWidgetState extends State<SecuritySectionWidget> {
),
),
sectionOptionSpacing,
]);
if (Platform.isAndroid) {
children.addAll(
[
MenuItemWidget(
captionedTextWidget: const CaptionedTextWidget(
title: "Hide from recents",
),
trailingSwitch: ToggleSwitchWidget(
value: _config.shouldHideFromRecents(),
onChanged: (value) async {
if (value) {
final AlertDialog alert = AlertDialog(
title: const Text("Hide from recents?"),
content: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text(
"Hiding from the task switcher will prevent you from taking screenshots in this app.",
style: TextStyle(
height: 1.5,
),
),
Padding(padding: EdgeInsets.all(8)),
Text(
"Are you sure?",
style: TextStyle(
height: 1.5,
),
),
],
),
),
actions: [
TextButton(
child: Text(
"No",
style: TextStyle(
color:
Theme.of(context).colorScheme.defaultTextColor,
),
),
onPressed: () {
Navigator.of(context, rootNavigator: true)
.pop('dialog');
},
),
TextButton(
child: Text(
"Yes",
style: TextStyle(
color:
Theme.of(context).colorScheme.defaultTextColor,
),
),
onPressed: () async {
Navigator.of(context, rootNavigator: true)
.pop('dialog');
await _config.setShouldHideFromRecents(true);
await FlutterWindowManager.addFlags(
FlutterWindowManager.FLAG_SECURE,
);
setState(() {});
},
),
],
);
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
} else {
await _config.setShouldHideFromRecents(false);
await FlutterWindowManager.clearFlags(
FlutterWindowManager.FLAG_SECURE,
);
setState(() {});
}
},
),
),
sectionOptionSpacing,
],
);
}
children.addAll([
MenuItemWidget(
captionedTextWidget: const CaptionedTextWidget(
title: "Active sessions",

View File

@@ -2,6 +2,7 @@
import 'package:ente_auth/core/constants.dart';
import 'package:ente_auth/core/logging/super_logging.dart';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/theme/ente_theme.dart';
import 'package:ente_auth/ui/components/captioned_text_widget.dart';
import 'package:ente_auth/ui/components/expandable_menu_item_widget.dart';
@@ -21,20 +22,22 @@ class SupportSectionWidget extends StatefulWidget {
class _SupportSectionWidgetState extends State<SupportSectionWidget> {
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return ExpandableMenuItemWidget(
title: "Support",
title: l10n.support,
selectionOptionsWidget: _getSectionOptions(context),
leadingIcon: Icons.help_outline_outlined,
);
}
Widget _getSectionOptions(BuildContext context) {
final l10n = context.l10n;
return Column(
children: [
sectionOptionSpacing,
MenuItemWidget(
captionedTextWidget: const CaptionedTextWidget(
title: "Email",
captionedTextWidget: CaptionedTextWidget(
title: l10n.email,
),
pressedColor: getEnteColorScheme(context).fillFaint,
trailingIcon: Icons.chevron_right_outlined,
@@ -45,14 +48,14 @@ class _SupportSectionWidgetState extends State<SupportSectionWidget> {
),
sectionOptionSpacing,
MenuItemWidget(
captionedTextWidget: const CaptionedTextWidget(
title: "Report a bug",
captionedTextWidget: CaptionedTextWidget(
title: l10n.reportABug,
),
pressedColor: getEnteColorScheme(context).fillFaint,
trailingIcon: Icons.chevron_right_outlined,
trailingIconIsMuted: true,
onTap: () async {
await sendLogs(context, "Report bug", "auth@ente.io");
await sendLogs(context, l10n.reportBug, "auth@ente.io");
},
onDoubleTap: () async {
final zipFilePath = await getZippedLogsFile(context);
@@ -61,8 +64,8 @@ class _SupportSectionWidgetState extends State<SupportSectionWidget> {
),
sectionOptionSpacing,
MenuItemWidget(
captionedTextWidget: const CaptionedTextWidget(
title: "Crash & error reporting",
captionedTextWidget: CaptionedTextWidget(
title: l10n.crashAndErrorReporting,
),
trailingSwitch: ToggleSwitchWidget(
value: SuperLogging.shouldReportErrors(),

View File

@@ -73,6 +73,7 @@ class _ThemeSwitchWidgetState extends State<ThemeSwitchWidget> {
pressedColor: getEnteColorScheme(context).fillFaint,
isExpandable: false,
trailingIcon: currentThemeMode == themeMode ? Icons.check : null,
trailingExtraMargin: 4,
onTap: () async {
AdaptiveTheme.of(context).setThemeMode(themeMode);
currentThemeMode = themeMode;

View File

@@ -1,3 +1,4 @@
import 'package:ente_auth/l10n/l10n.dart';
import 'package:flutter/material.dart';
class SettingsTitleBarWidget extends StatelessWidget {
@@ -5,6 +6,7 @@ class SettingsTitleBarWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return Container(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Padding(
@@ -19,7 +21,7 @@ class SettingsTitleBarWidget extends StatelessWidget {
},
icon: const Icon(Icons.keyboard_double_arrow_left_outlined),
),
const Text("Settings"),
Text(l10n.settings),
],
),
),

View File

@@ -3,6 +3,7 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
/// A widget which handles app lifecycle events for showing and hiding a lock screen.
/// This should wrap around a `MyApp` widget (or equivalent).
@@ -107,6 +108,8 @@ class _AppLockState extends State<AppLock> with WidgetsBindingObserver {
themeMode: ThemeMode.system,
theme: widget.lightTheme,
darkTheme: widget.darkTheme,
supportedLocales: AppLocalizations.supportedLocales,
localizationsDelegates: AppLocalizations.localizationsDelegates,
onGenerateRoute: (settings) {
switch (settings.name) {
case '/lock-screen':

View File

@@ -59,7 +59,7 @@ class _LockScreenState extends State<LockScreen> {
_logger.info("Showing lockscreen");
try {
final result = await requestAuthentication(
"Please authenticate to view your memories",
"Please authenticate to view your secrets",
);
if (result) {
AppLock.of(context).didUnlock();

View File

@@ -1,5 +1,6 @@
// @dart=2.9
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/services/user_service.dart';
import 'package:ente_auth/ui/lifecycle_event_handler.dart';
import 'package:flutter/material.dart';
@@ -47,10 +48,11 @@ class _TwoFactorAuthenticationPageState
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return Scaffold(
appBar: AppBar(
title: const Text(
"Two-factor authentication",
title: Text(
l10n.twoFactorAuthTitle,
),
),
body: _getBody(),
@@ -58,6 +60,7 @@ class _TwoFactorAuthenticationPageState
}
Widget _getBody() {
final l10n = context.l10n;
final pinPutDecoration = BoxDecoration(
border: Border.all(
color: Theme.of(context)
@@ -73,9 +76,9 @@ class _TwoFactorAuthenticationPageState
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
const Text(
"Enter the 6-digit code from\nyour authenticator app",
style: TextStyle(
Text(
l10n.enterCodeHint,
style: const TextStyle(
height: 1.4,
fontSize: 16,
),
@@ -121,7 +124,7 @@ class _TwoFactorAuthenticationPageState
_verifyTwoFactorCode(_code);
}
: null,
child: const Text("Verify"),
child: Text(l10n.verify),
),
),
const Padding(padding: EdgeInsets.all(30)),
@@ -132,10 +135,10 @@ class _TwoFactorAuthenticationPageState
},
child: Container(
padding: const EdgeInsets.all(10),
child: const Center(
child: Center(
child: Text(
"Lost device?",
style: TextStyle(
l10n.lostDeviceTitle,
style: const TextStyle(
decoration: TextDecoration.underline,
fontSize: 12,
),

View File

@@ -2,6 +2,7 @@
import 'dart:ui';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/services/user_service.dart';
import 'package:ente_auth/utils/dialog_util.dart';
import 'package:flutter/material.dart';
@@ -27,11 +28,12 @@ class _TwoFactorRecoveryPageState extends State<TwoFactorRecoveryPage> {
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return Scaffold(
appBar: AppBar(
title: const Text(
"Recover account",
style: TextStyle(
title: Text(
l10n.recoverAccount,
style: const TextStyle(
fontSize: 18,
),
),
@@ -44,9 +46,9 @@ class _TwoFactorRecoveryPageState extends State<TwoFactorRecoveryPage> {
Padding(
padding: const EdgeInsets.fromLTRB(60, 0, 60, 0),
child: TextFormField(
decoration: const InputDecoration(
hintText: "Enter your recovery key",
contentPadding: EdgeInsets.all(20),
decoration: InputDecoration(
hintText: l10n.enterRecoveryKeyHint,
contentPadding: const EdgeInsets.all(20),
),
style: const TextStyle(
fontSize: 14,
@@ -79,7 +81,7 @@ class _TwoFactorRecoveryPageState extends State<TwoFactorRecoveryPage> {
);
}
: null,
child: const Text("Recover"),
child: Text(l10n.recover),
),
),
GestureDetector(
@@ -87,15 +89,15 @@ class _TwoFactorRecoveryPageState extends State<TwoFactorRecoveryPage> {
onTap: () {
showErrorDialog(
context,
"Contact support",
"Please drop an email to support@ente.io from your registered email address",
l10n.contactSupport,
l10n.contactSupportViaEmailMessage("support@ente.io"),
);
},
child: Container(
padding: const EdgeInsets.all(40),
child: Center(
child: Text(
"No recovery key?",
l10n.noRecoveryKeyTitle,
style: TextStyle(
decoration: TextDecoration.underline,
fontSize: 12,

View File

@@ -3,6 +3,7 @@
import 'dart:math';
import 'package:confetti/confetti.dart';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/ui/common/loading_widget.dart';
import 'package:ente_auth/ui/common/progress_dialog.dart';
import 'package:flutter/material.dart';
@@ -32,6 +33,7 @@ Future<dynamic> showErrorDialog(
String title,
String content,
) {
final l10n = context.l10n;
final AlertDialog alert = AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
title: title.isEmpty
@@ -44,7 +46,7 @@ Future<dynamic> showErrorDialog(
actions: [
TextButton(
child: Text(
"Ok",
l10n.ok,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
),

View File

@@ -7,6 +7,7 @@ import 'package:email_validator/email_validator.dart';
import 'package:ente_auth/core/configuration.dart';
import 'package:ente_auth/core/logging/super_logging.dart';
import 'package:ente_auth/ente_theme_data.dart';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/ui/common/dialogs.dart';
import 'package:ente_auth/ui/tools/debug/log_file_viewer.dart';
// import 'package:ente_auth/ui/tools/debug/log_file_viewer.dart';
@@ -37,6 +38,7 @@ Future<void> sendLogs(
String subject,
String body,
}) async {
final l10n = context.l10n;
final List<Widget> actions = [
TextButton(
child: Row(
@@ -48,7 +50,7 @@ Future<void> sendLogs(
),
const Padding(padding: EdgeInsets.all(4)),
Text(
"View logs",
l10n.viewLogsAction,
style: TextStyle(
color: Theme.of(context)
.colorScheme
@@ -88,11 +90,9 @@ Future<void> sendLogs(
final List<Widget> content = [];
content.addAll(
[
const Text(
"This will send across logs to help us debug your issue. "
"While we take precautions to ensure that sensitive information is not "
"logged, we encourage you to view these logs before sharing them.",
style: TextStyle(
Text(
l10n.sendLogsDescription,
style: const TextStyle(
height: 1.5,
fontSize: 16,
),
@@ -148,7 +148,8 @@ Future<void> _sendLogs(
}
Future<String> getZippedLogsFile(BuildContext context) async {
final dialog = createProgressDialog(context, "Preparing logs...");
final l10n = context.l10n;
final dialog = createProgressDialog(context, l10n.preparingLogsTitle);
await dialog.show();
final logsPath = (await getApplicationSupportDirectory()).path;
final logsDirectory = Directory(logsPath + "/logs");
@@ -168,12 +169,13 @@ Future<void> shareLogs(
String toEmail,
String zipFilePath,
) async {
final l10n = context.l10n;
final result = await showChoiceDialog(
context,
"Email logs",
"Please send the logs to $toEmail",
firstAction: "Copy email",
secondAction: "Export logs",
l10n.emailLogsTitle,
l10n.emailLogsMessage(toEmail),
firstAction: l10n.copyEmailAction,
secondAction: l10n.exportLogsAction,
);
if (result != null && result == DialogUserChoice.firstChoice) {
await Clipboard.setData(ClipboardData(text: toEmail));
@@ -237,21 +239,22 @@ Future<String> _clientInfo() async {
}
void _showNoMailAppsDialog(BuildContext context, String toEmail) {
final l10n = context.l10n;
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Please email us at $toEmail'),
title: Text(l10n.emailUsMessage(toEmail)),
actions: <Widget>[
TextButton(
child: const Text("Copy email"),
child: Text(l10n.copyEmailAction),
onPressed: () async {
await Clipboard.setData(ClipboardData(text: toEmail));
showShortToast(context, 'Copied');
showShortToast(context, l10n.copied);
},
),
TextButton(
child: const Text("OK"),
child: Text(l10n.ok),
onPressed: () {
Navigator.pop(context);
},

View File

@@ -9,10 +9,10 @@ import connectivity_macos
import flutter_local_notifications
import flutter_secure_storage_macos
import package_info_plus_macos
import path_provider_macos
import path_provider_foundation
import sentry_flutter
import share_plus_macos
import shared_preferences_macos
import shared_preferences_foundation
import sqflite
import url_launcher_macos

View File

@@ -7,7 +7,7 @@ packages:
name: _fe_analyzer_shared
url: "https://pub.dartlang.org"
source: hosted
version: "40.0.0"
version: "47.0.0"
adaptive_theme:
dependency: "direct main"
description:
@@ -21,21 +21,21 @@ packages:
name: analyzer
url: "https://pub.dartlang.org"
source: hosted
version: "4.1.0"
version: "4.7.0"
archive:
dependency: transitive
description:
name: archive
url: "https://pub.dartlang.org"
source: hosted
version: "3.3.1"
version: "3.3.5"
args:
dependency: transitive
description:
name: args
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.1"
version: "2.3.2"
async:
dependency: transitive
description:
@@ -63,14 +63,14 @@ packages:
name: bloc
url: "https://pub.dartlang.org"
source: hosted
version: "8.0.3"
version: "8.1.0"
bloc_test:
dependency: "direct dev"
description:
name: bloc_test
url: "https://pub.dartlang.org"
source: hosted
version: "9.0.3"
version: "9.1.0"
boolean_selector:
dependency: transitive
description:
@@ -84,14 +84,14 @@ packages:
name: build
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.0"
version: "2.3.1"
build_config:
dependency: transitive
description:
name: build_config
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
version: "1.1.1"
build_daemon:
dependency: transitive
description:
@@ -105,21 +105,21 @@ packages:
name: build_resolvers
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.9"
version: "2.0.10"
build_runner:
dependency: "direct dev"
description:
name: build_runner
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.11"
version: "2.3.0"
build_runner_core:
dependency: transitive
description:
name: build_runner_core
url: "https://pub.dartlang.org"
source: hosted
version: "7.2.3"
version: "7.2.7"
built_collection:
dependency: transitive
description:
@@ -133,7 +133,7 @@ packages:
name: built_value
url: "https://pub.dartlang.org"
source: hosted
version: "8.3.2"
version: "8.4.3"
characters:
dependency: transitive
description:
@@ -147,7 +147,7 @@ packages:
name: checked_yaml
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
version: "2.0.2"
clipboard:
dependency: "direct main"
description:
@@ -168,7 +168,7 @@ packages:
name: code_builder
url: "https://pub.dartlang.org"
source: hosted
version: "4.1.0"
version: "4.4.0"
collection:
dependency: "direct main"
description:
@@ -224,14 +224,21 @@ packages:
name: convert
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.2"
version: "3.1.1"
coverage:
dependency: transitive
description:
name: coverage
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.2"
version: "1.6.2"
cross_file:
dependency: transitive
description:
name: cross_file
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.3+2"
crypto:
dependency: transitive
description:
@@ -259,14 +266,14 @@ packages:
name: dart_style
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.3"
version: "2.2.4"
dbus:
dependency: transitive
description:
name: dbus
url: "https://pub.dartlang.org"
source: hosted
version: "0.7.4"
version: "0.7.8"
device_info:
dependency: "direct main"
description:
@@ -301,7 +308,7 @@ packages:
name: dotted_border
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0+2"
version: "2.0.0+3"
email_validator:
dependency: "direct main"
description:
@@ -343,21 +350,21 @@ packages:
name: ffi
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.1"
version: "2.0.1"
file:
dependency: transitive
description:
name: file
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.2"
version: "6.1.4"
file_picker:
dependency: "direct main"
description:
name: file_picker
url: "https://pub.dartlang.org"
source: hosted
version: "4.6.1"
version: "5.2.5"
fixnum:
dependency: transitive
description:
@@ -383,28 +390,28 @@ packages:
name: flutter_animation_progress_bar
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.1"
version: "2.3.1"
flutter_bloc:
dependency: "direct main"
description:
name: flutter_bloc
url: "https://pub.dartlang.org"
source: hosted
version: "8.0.1"
version: "8.1.1"
flutter_email_sender:
dependency: "direct main"
description:
name: flutter_email_sender
url: "https://pub.dartlang.org"
source: hosted
version: "5.1.0"
version: "5.2.0"
flutter_inappwebview:
dependency: "direct main"
description:
name: flutter_inappwebview
url: "https://pub.dartlang.org"
source: hosted
version: "5.7.1"
version: "5.7.2+3"
flutter_launcher_icons:
dependency: "direct main"
description:
@@ -418,14 +425,14 @@ packages:
name: flutter_local_notifications
url: "https://pub.dartlang.org"
source: hosted
version: "12.0.3"
version: "12.0.4"
flutter_local_notifications_linux:
dependency: transitive
description:
name: flutter_local_notifications_linux
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
version: "2.0.0"
flutter_local_notifications_platform_interface:
dependency: transitive
description:
@@ -444,7 +451,7 @@ packages:
name: flutter_native_splash
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.13"
version: "2.2.16"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
@@ -458,42 +465,42 @@ packages:
name: flutter_secure_storage
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.0"
version: "6.1.0"
flutter_secure_storage_linux:
dependency: transitive
description:
name: flutter_secure_storage_linux
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
version: "1.1.2"
flutter_secure_storage_macos:
dependency: transitive
description:
name: flutter_secure_storage_macos
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
version: "1.1.2"
flutter_secure_storage_platform_interface:
dependency: transitive
description:
name: flutter_secure_storage_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
version: "1.0.1"
flutter_secure_storage_web:
dependency: transitive
description:
name: flutter_secure_storage_web
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
version: "1.1.1"
flutter_secure_storage_windows:
dependency: transitive
description:
name: flutter_secure_storage_windows
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.2"
version: "1.1.3"
flutter_slidable:
dependency: "direct main"
description:
@@ -504,9 +511,11 @@ packages:
flutter_sodium:
dependency: "direct main"
description:
name: flutter_sodium
url: "https://pub.dartlang.org"
source: hosted
path: "."
ref: HEAD
resolved-ref: "267435eaf07af60b94406adf14bedf21e08a6b4f"
url: "https://github.com/ente-io/flutter_sodium.git"
source: git
version: "0.2.0"
flutter_speed_dial:
dependency: "direct main"
@@ -525,20 +534,13 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_windowmanager:
dependency: "direct main"
description:
name: flutter_windowmanager
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
fluttertoast:
dependency: "direct main"
description:
name: fluttertoast
url: "https://pub.dartlang.org"
source: hosted
version: "8.1.1"
version: "8.1.2"
frontend_server_client:
dependency: transitive
description:
@@ -552,7 +554,7 @@ packages:
name: glob
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
version: "2.1.1"
google_nav_bar:
dependency: "direct main"
description:
@@ -566,7 +568,7 @@ packages:
name: graphs
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.2.0"
hex:
dependency: transitive
description:
@@ -594,21 +596,21 @@ packages:
name: http_multi_server
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.0"
version: "3.2.1"
http_parser:
dependency: transitive
description:
name: http_parser
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.1"
version: "4.0.2"
image:
dependency: transitive
description:
name: image
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.2"
version: "3.3.0"
intl:
dependency: "direct main"
description:
@@ -622,7 +624,7 @@ packages:
name: io
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
version: "1.0.4"
js:
dependency: transitive
description:
@@ -636,14 +638,14 @@ packages:
name: json_annotation
url: "https://pub.dartlang.org"
source: hosted
version: "4.5.0"
version: "4.7.0"
json_serializable:
dependency: "direct dev"
description:
name: json_serializable
url: "https://pub.dartlang.org"
source: hosted
version: "6.2.0"
version: "6.5.4"
lints:
dependency: "direct dev"
description:
@@ -664,7 +666,7 @@ packages:
name: logging
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
version: "1.1.0"
matcher:
dependency: transitive
description:
@@ -692,7 +694,7 @@ packages:
name: mime
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
version: "1.0.4"
mocktail:
dependency: "direct dev"
description:
@@ -721,27 +723,34 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
open_filex:
dependency: "direct main"
description:
name: open_filex
url: "https://pub.dartlang.org"
source: hosted
version: "4.3.2"
otp:
dependency: "direct main"
description:
name: otp
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.1"
version: "3.1.3"
package_config:
dependency: transitive
description:
name: package_config
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
version: "2.1.0"
package_info_plus:
dependency: "direct main"
description:
name: package_info_plus
url: "https://pub.dartlang.org"
source: hosted
version: "1.4.2"
version: "1.4.3+1"
package_info_plus_linux:
dependency: transitive
description:
@@ -769,14 +778,14 @@ packages:
name: package_info_plus_web
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.5"
version: "1.0.6"
package_info_plus_windows:
dependency: transitive
description:
name: package_info_plus_windows
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.5"
version: "2.1.0"
password_strength:
dependency: "direct main"
description:
@@ -811,21 +820,21 @@ packages:
name: path_provider
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.11"
version: "2.0.12"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.20"
path_provider_ios:
version: "2.0.22"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_ios
name: path_provider_foundation
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.11"
version: "2.1.1"
path_provider_linux:
dependency: transitive
description:
@@ -833,34 +842,27 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.7"
path_provider_macos:
dependency: transitive
description:
name: path_provider_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.6"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
version: "2.0.5"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.7"
version: "2.1.3"
petitparser:
dependency: transitive
description:
name: petitparser
url: "https://pub.dartlang.org"
source: hosted
version: "5.0.0"
version: "5.1.0"
pinput:
dependency: "direct main"
description:
@@ -895,7 +897,7 @@ packages:
name: pool
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.0"
version: "1.5.1"
process:
dependency: transitive
description:
@@ -909,21 +911,21 @@ packages:
name: provider
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.3"
version: "6.0.5"
pub_semver:
dependency: transitive
description:
name: pub_semver
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
version: "2.1.3"
pubspec_parse:
dependency: transitive
description:
name: pubspec_parse
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "1.2.1"
qr_code_scanner:
dependency: "direct main"
description:
@@ -937,28 +939,28 @@ packages:
name: sentry
url: "https://pub.dartlang.org"
source: hosted
version: "6.15.1"
version: "6.19.0"
sentry_flutter:
dependency: "direct main"
description:
name: sentry_flutter
url: "https://pub.dartlang.org"
source: hosted
version: "6.15.1"
version: "6.19.0"
share_plus:
dependency: "direct main"
description:
name: share_plus
url: "https://pub.dartlang.org"
source: hosted
version: "4.4.0"
version: "4.5.3"
share_plus_linux:
dependency: transitive
description:
name: share_plus_linux
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
version: "3.0.1"
share_plus_macos:
dependency: transitive
description:
@@ -972,14 +974,14 @@ packages:
name: share_plus_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.3"
version: "3.2.0"
share_plus_web:
dependency: transitive
description:
name: share_plus_web
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
version: "3.1.0"
share_plus_windows:
dependency: transitive
description:
@@ -993,35 +995,28 @@ packages:
name: shared_preferences
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.15"
version: "2.0.17"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.13"
shared_preferences_ios:
version: "2.0.15"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_ios
name: shared_preferences_foundation
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
version: "2.1.2"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
shared_preferences_macos:
dependency: transitive
description:
name: shared_preferences_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
version: "2.1.3"
shared_preferences_platform_interface:
dependency: transitive
description:
@@ -1042,35 +1037,35 @@ packages:
name: shared_preferences_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
version: "2.1.3"
shelf:
dependency: transitive
description:
name: shelf
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
version: "1.4.0"
shelf_packages_handler:
dependency: transitive
description:
name: shelf_packages_handler
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
version: "3.0.1"
shelf_static:
dependency: transitive
description:
name: shelf_static
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.1.1"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
version: "1.0.3"
sky_engine:
dependency: transitive
description: flutter
@@ -1082,28 +1077,28 @@ packages:
name: source_gen
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.2"
version: "1.2.6"
source_helper:
dependency: transitive
description:
name: source_helper
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.2"
version: "1.3.3"
source_map_stack_trace:
dependency: transitive
description:
name: source_map_stack_trace
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.1.1"
source_maps:
dependency: transitive
description:
name: source_maps
url: "https://pub.dartlang.org"
source: hosted
version: "0.10.10"
version: "0.10.11"
source_span:
dependency: transitive
description:
@@ -1117,14 +1112,14 @@ packages:
name: sqflite
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.2.3"
sqflite_common:
dependency: transitive
description:
name: sqflite_common
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.0"
version: "2.4.1"
stack_trace:
dependency: transitive
description:
@@ -1152,7 +1147,7 @@ packages:
name: stream_transform
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
version: "2.1.0"
string_scanner:
dependency: transitive
description:
@@ -1166,7 +1161,7 @@ packages:
name: synchronized
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0+3"
version: "3.0.1"
term_glyph:
dependency: transitive
description:
@@ -1201,14 +1196,14 @@ packages:
name: timezone
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.0"
version: "0.9.1"
timing:
dependency: transitive
description:
name: timing
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
version: "1.0.1"
typed_data:
dependency: transitive
description:
@@ -1229,63 +1224,63 @@ packages:
name: url_launcher
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.5"
version: "6.1.8"
url_launcher_android:
dependency: transitive
description:
name: url_launcher_android
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.19"
version: "6.0.23"
url_launcher_ios:
dependency: transitive
description:
name: url_launcher_ios
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.17"
version: "6.0.18"
url_launcher_linux:
dependency: transitive
description:
name: url_launcher_linux
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
version: "3.0.2"
url_launcher_macos:
dependency: transitive
description:
name: url_launcher_macos
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
version: "3.0.2"
url_launcher_platform_interface:
dependency: transitive
description:
name: url_launcher_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.1.1"
url_launcher_web:
dependency: transitive
description:
name: url_launcher_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.13"
version: "2.0.14"
url_launcher_windows:
dependency: transitive
description:
name: url_launcher_windows
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
version: "3.0.3"
uuid:
dependency: "direct main"
description:
name: uuid
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.6"
version: "3.0.7"
vector_math:
dependency: transitive
description:
@@ -1299,42 +1294,42 @@ packages:
name: vm_service
url: "https://pub.dartlang.org"
source: hosted
version: "8.3.0"
version: "9.4.0"
watcher:
dependency: transitive
description:
name: watcher
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
version: "1.0.2"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.0"
version: "2.3.0"
webkit_inspection_protocol:
dependency: transitive
description:
name: webkit_inspection_protocol
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.2.0"
win32:
dependency: transitive
description:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "2.6.1"
version: "3.1.3"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0+2"
version: "0.2.0+3"
xml:
dependency: transitive
description:
@@ -1351,4 +1346,4 @@ packages:
version: "3.1.1"
sdks:
dart: ">=2.18.0 <3.0.0"
flutter: ">=3.3.0-0"
flutter: ">=3.3.0"

View File

@@ -1,6 +1,6 @@
name: ente_auth
description: ente two-factor authenticator
version: 1.0.21+21
version: 1.0.25+26
publish_to: none
environment:
@@ -23,7 +23,7 @@ dependencies:
event_bus: ^2.0.0
expandable: ^5.0.1
expansion_tile_card: ^2.0.0
file_picker: ^4.6.1
file_picker: ^5.2.4
fk_user_agent: ^2.1.0
flutter:
sdk: flutter
@@ -38,9 +38,10 @@ dependencies:
flutter_native_splash: ^2.2.13
flutter_secure_storage: ^6.0.0
flutter_slidable: ^2.0.0
flutter_sodium: ^0.2.0
flutter_sodium:
git:
url: https://github.com/ente-io/flutter_sodium.git
flutter_speed_dial: ^6.2.0
flutter_windowmanager: ^0.2.0
fluttertoast: ^8.1.1
google_nav_bar: ^5.0.5 #supported
http: ^0.13.4
@@ -49,7 +50,7 @@ dependencies:
local_auth: ^1.1.5
logging: ^1.0.1
move_to_background: ^1.0.2
# open_file: ^3.2.1 Disabled to please PlayStore overlords
open_filex: ^4.3.2
otp: ^3.1.1
package_info_plus: ^1.0.1
password_strength: ^0.2.0