- This commit introduces CalendarInfoBase as a base type to hold common fields between CalendarInfo and BirthdayCalendarInfo
- It also makes CalendarModel provide the available calendars.
- SearchViewModel dependency on the locator is removed and CalendarModel is now injected.
With our new approach we no longer need to set up and store the birthday calendar locally.
Color will be stored in the server and name won't be editable.
Co-authored-by: bed <bed@tutao.de>
We want to use offline storage (SQLite) for autosaved drafts as it will
allow the locally saved draft to be accessible when offline. This means
we refactor ConfigurationDatabase.
We still want to use the same encoding methods, as it provides a simple
way to put in data without having to worry about making some complex
schema.
Closes#9743
Co-authored-by: ivk <ivk@tutao.de>
- Remove the ability to customize all colors, instead only allowing the
user to choose the base theme (light/dark) and the source color from
which the theme will be generated.
- Adjust newToOldColorTokenMap to correctly render new Material 3 theme
on old clients.
- Generate new Material 3 theme from old whitelabel config for non admin
users.
- Migrate whitelabel to new Material 3 theme post login of admin.
Close#9459
Co-authored-by: paw <paw-hub@users.noreply.github.com>
Co-authored-by: hrb-hub <hrb-hub@users.noreply.github.com>
Co-authored-by: ivk <ivk@tutao.de>
Every five seconds while the user is typing, save a local copy of the
draft to ConfigurationDatabase.
If the draft has not been touched for five minutes, it gets uploaded to
the server.
If the user restarts the client with an autosaved draft, it will open
automatically. Only one draft can be autosaved at a time.
Additionally, if an entity update for a draft is received while the user
has that draft open for editing, saving will prompt a confirmation
dialog to overwrite the draft on the server, as this draft data may be
outdated.
Next, if the user attempts to open a new draft while there is an
autosaved draft, display a confirmation dialog to the user to delete
it.
And lastly, if the user has two separate drafts open on different
windows, we handle this by preventing saving over them.
Closes#4419
After the group was shared it was not possible to change the original
name anymore, neither for the owner nor for participants.
Show groupInfo name in the editing dialog for shared groups
Add GroupSettingsModel for editing the name of groups
Used in ContactList, Templates, and Calendar
Do not set name on groupSettings when accepting invitation, so that
groupInfo name take priority
Closes: #8639
Co-authored-by: ivk <ivk@tutao.de>
This commit modifies the list-unsubscribe flow for unsubscription from
newsletters, with the following scenarios:
- Link with POST: The mail has a link and a List-Unsubscribe-Post header
to allow one-click unsubscribe. In that case, we send the POST request
from the client for the Desktop, iOS, and Android app. For the web app,
we send the link to the server and do a ListUnsubscribeService request.
- Link with GET: The mail has a link but does not allow one-click
unsubscribe. In this case, we show a dialog which has the option to open
the link in the browser.
- Link with mailto: The mail does not have a http link in the
list-unsubscribe header, but it has a mailto link for unsubscription.
In this case, we show a dialog which has the option to open a new mail
dialog which uses the mailto link.
Co-authored-by: das <das@tutao.de>
Co-authored-by: jomapp <17314077+jomapp@users.noreply.github.com>
Co-authored-by: sug <sug@tutao.de>
Co-authored-by: kib <104761667+kibibytium@users.noreply.github.com>
MailViewModel should not be used outside of mail view, e.g. in search.
Extract generic UndoModel that can be reused for various undo actions.
Pull some move actions up to the top level to use it.
* split PublicKeyProvider into PublicIdentityKeyProvider and PublicEncryptionKeyProvider
* move database queries to new IdentityKeyTrustDatabase
* only have one function loading public identity key and directly load from server if not in trust db (and add to trust db in this case) in PublicIdentityKeyProvider
* KeyVerificationFacade.verify() only needs to be called once to get a valid verification state
* introduce Not_Supported as source of trust (for web client)
* introduce Not_Supported verification state (e.g. for web client and when loading via group id)
* and handle Not_Supported verification state in the RecipientsModel (presentable state is none because verification was not available)
implement PublicKeySignatueFacade to encode public encryption keys and sign them
sign public encryption keys where it is needed (e.g. key rotation, identity key pair creation)
add ecc keys to current rsa key pairs when creating identity key pairs
refactor GroupManagementFacade, extract loading keys via admin group key, extract creation of identity key pairs
tuta#2083
tuta#2106
* display own identity key and default sender
* support scanning identity keys using qr codes
* service to request identity keys
* rework key verification database for identity keys
Co-authored-by: bedhub <bedhub@users.noreply.github.com>
Co-authored-by: mab <mab@tutao.de>
Show a snackbar that can undo moving mails. The user can click "Undo" or
press CTRL-Z (CMD-Z) to undo moving mails. If they do, this will move
the mails back and close the snackbar. Additionally, if the mails were
to be reported as spam, they won't be reported, either.
Removed the reporting snackbar and added a new message specifically
for mails being moved to spam.
Close#9321Close#9319Close#9318Close#9312Close#9205Close#9386Close#9428
Co-authored-by: paw <paw-hub@users.noreply.github.com>
Co-authored-by: hrb-hub <hrb-hub@users.noreply.github.com>
Lazyload EventBannerImpl.ts to allow EventBanner.ts to stay with MailView
Adds a new directory mail-app/gui/date to date-gui chunk allowing calendar
related ui to stay inside mail-app folder structure.
Co-authored-by: ivk <ivk@tutao.de>
Surrounding a query in quotes has a different meaning between FTS5 and
IndexedDb searching. We don't want to expose which search model we are
using in this case, so we can just create a simple ContactSearchFacade
that handles any backend-specific details.
This simplifies a few details, like ContactModel originally needing a
lambda now only needing a ContactSearchFacade.
Avoid loading contacts one by one in ContactModel, make the control flow
clearer.
Closes#9088
Co-authored-by: ivk <ivk@tutao.de>
Co-authored-by: hrb-hub <hrb-hub@users.noreply.github.com>
When searching, we need to highlight the text matching the search query.
Added "beforeSanitizeElements" in HTMLSanitizer to handle highlighting
search queries inline of text bodies. This will handle both exact and
non-exact (partial) matches depending on quotes inside the query.
Close#8883
Co-authored-by: paw <paw-hub@users.noreply.github.com>
Search extends range on login based on the OfflineTimeRangeDate
Extending search range extends OfflineTimeRangeDate
Co-authored-by: ivk <ivk@tutao.de>
Close#8549
- Introduce a separate Indexer for SQLite using FTS5
- Split search backends and use the right one based on client (IndexedDB
for Browser, and OfflineStorage everywhere else)
- Split SearchFacade into two implementations
- Adds a table for storing unindexed metadata for mails
- Escape special character for SQLite search
To escape special characters from fts5 syntax. However, simply
surrounding each token in quotes is sufficient to do this.
See section 3.1 "FTS5 Strings" here: https://www.sqlite.org/fts5.html
which states that a string may be specified by surrounding it in
quotes, and that special string requirements only exist for strings
that are not in quotes.
- Add EncryptedDbWrapper
- Simplify out of sync logic in IndexedDbIndexer
- Fix deadlock when initializing IndexedDbIndexer
- Cleanup indexedDb index when migrating to offline storage index
- Pass contactSuggestionFacade to IndexedDbSearchFacade
The only suggestion facade used by IndexedDbSearchFacade was the
contact suggestion facade. So we made it clearer.
- Remove IndexerCore stats
- Split custom cache handlers into separate files
We were already doing this with user, so we should do this with the
other entity types.
- Rewrite IndexedDb tests
- Add OfflineStorage indexer tests
- Add custom cache handlers tests to OfflineStorageTest
- Add tests for custom cache handlers with ephemeral storage
- Use dbStub instead of dbMock in IndexedDbIndexerTest
- Replace spy with testdouble in IndexedDbIndexerTest
Close#8550
Co-authored-by: ivk <ivk@tutao.de>
Co-authored-by: paw <paw-hub@users.noreply.github.com>
Co-authored-by: wrd <wrd@tutao.de>
Co-authored-by: bir <bir@tutao.de>
Co-authored-by: hrb-hub <hrb-hub@users.noreply.github.com>
We observed clients that managed to get stuck with a missing server
model, which made login from stored credentials impossible and required
getting a new session.
The reason was that only the service executor, rest client and event bus
client cared to update the server model if they were missing.
However, the offline database also stores data in the server's model and
thus requires it to read any data. Since logging in will hit
the cache before requesting the server, a corrupted or missing server
model causes us to not be able to log in.
This commit gives the responsibility of acquiring the models to
ServerModelInfo.resolveServerTypeReference if they are missing or out
of date to avoid situations where we call resolveServerTypeReference
without first checking if the model is initialized.
Additionally, we show a dialog to the user if the models cannot be
initialized instead of an uncaught error.
We considered having the error handler try to repeat model
initialization, but since the original request already failed at that
point, getting back to a normal state would require an extra manual
retry.
fix#9004
Co-authored-by: nig <nig@tutao.de>
Co-authored-by: sug <sug@tutao.de>
Co-authored-by: kib <104761667+kibibytium@users.noreply.github.com>
Passing instances explicitly avoids the situations where some of them
might not be initialized.
We also simplified the entity handling by converting entity updates to
data with resolved types early so that the listening code doesn't have
to deal with it.
We did fix some of the bad test practices, e.g. setting/restoring env
incorrectly. This matters now because accessors for type model
initializers check env.mode.
Co-authored-by: paw <paw-hub@users.noreply.github.com>
- This list model groups all emails by conversation in the mail list
- Also adds setting for grouping by conversation (i.e. enables this)
- The setting is overridden for SENT and DRAFT folder types (it uses the
other per-mail list model instead)
- Adds MailSetListModel which provides a common interface for the
MailViewModel so that additional list models can be created; it is
used for MailListModel and the new ConversationListModel, but it can
be extended to even more list models in the future if it is ever
desired.
Note: This does not include actions. Any action you do (delete, archive,
etc.) will be applied to the selected email. The purpose of this commit
is to just implement the list model. See #5051 for more information.
Closes#8223
Co-authored-by: bir <bir@tutao.de>
Co-authored-by: ivk <ivk@tutao.de>
Calendar subscriptions can collide with entity updates during
application startup. This commit adds a SyncTracker to track the
progress of initial entity updates, and after processing the entire
batch, mark the sync as done, allowing calendars to synchronize with
fewer chance to collisions.
In some cases LoginFacade does succeed with the partial login, but
some login actions fail on the page side, e.g. loading of
`TutanotaProperties`. This leads to an inconsistent state where the
worker is in the logged in state while the page context is not.
We solve the issue by catching the errors during page context init and
resetting the state on both sides.
In the future we could make the process more robust by loading all the
necessary parts in `LoginFacade` or making some parts lazy-loaded.
Fix#5537
we're moving to persisting the import state only on the server,
with the files to be imported on disk the only local state that
is kept by the importer.
Most errors happen during import preparation after we receive the files
to import. These can be caught & handled immediately. If no errors
happen, the remote state will be set up on the server at this stage and
can be subscribed to by the UI by loading it via its ID
Some other errors can happen asynchronously while the importer is
running in the background. For those, the importer sets a hook to
receive and handle them as they happen.
any normal state updates are sent to the server in node-mimimi and
received in the UI via entity updates.
Co-authored-by: nig <nig@tutao.de>
Co-authored-by: sug <sug@tutao.de>
Co-authored-by: map <mpfau@users.noreply.github.com>
Co-authored-by: jhm <17314077+jomapp@users.noreply.github.com>
Co-authored-by: Kinan <104761667+kibibytium@users.noreply.github.com>
Co-authored-by: abp <abp@tutao.de>
The reason for this refactor is to make it possible to put "data-testid"
attributes on HTML tags. Those attributes can be used with UI test
frameworks to make automated testing independent of the translation
language or text.
The idea is to get rid of the lazy<string> types and instead use a new type
called Translation wherever possible. Translation replaces the old
TranslationText and contains both translation key and translation text.
The type MaybeTranslation is a legacy type left to make the transition feasible.
It can be replaced with either TranslationKey or Translation in the future.
Co-authored-by: map <mpfau@users.noreply.github.com>