62 Commits

Author SHA1 Message Date
Burak Kaan Köse
f9c53ca2c9 New Crowdin updates (#724)
* New translations resources.json (Romanian)

* New translations resources.json (French)

* New translations resources.json (Spanish)

* New translations resources.json (Bulgarian)

* New translations resources.json (Catalan)

* New translations resources.json (Czech)

* New translations resources.json (Danish)

* New translations resources.json (German)

* New translations resources.json (Greek)

* New translations resources.json (Finnish)

* New translations resources.json (Italian)

* New translations resources.json (Japanese)

* New translations resources.json (Lithuanian)

* New translations resources.json (Dutch)

* New translations resources.json (Polish)

* New translations resources.json (Russian)

* New translations resources.json (Slovak)

* New translations resources.json (Turkish)

* New translations resources.json (Ukrainian)

* New translations resources.json (Chinese Simplified)

* New translations resources.json (Galician)

* New translations resources.json (Portuguese, Brazilian)

* New translations resources.json (Indonesian)
2025-07-30 23:43:07 +02:00
Burak Kaan Köse
21f9c7cf6d Deprecation of Application Insights for Sentry.IO (#723)
* Remove Application Insights implementation and implement new Sentry.IO SDK

* Remove test exception.
2025-07-30 23:36:10 +02:00
Maicol Battistini
43283b7218 feat(notification): Remove notification when read externally (#707)
* feat(notification):  Add notification removal feature

Implemented a new method `RemoveNotificationAsync` in the `INotificationBuilder` interface to allow the removal of toast notifications for specific emails identified by a unique ID.

This change enhances the notification management by ensuring that notifications can be cleared when emails are marked as read. The `NotificationBuilder` class has been updated to include logic for removing existing notifications and to use the unique ID as a tag for the toast notifications, facilitating their removal. Additionally, the `AppShellViewModel` has been modified to call this new method when an email is updated and marked as read.

This improvement aims to provide a better user experience by keeping the notification area relevant and up-to-date.

* feat(notification):  Add MailReadStatusChanged event handling

Introduced a new event system for handling email read status changes. This includes the addition of a listener in `NotificationBuilder` that removes notifications when an email is marked as read.

• Added `MailReadStatusChanged` record to represent the event.
• Registered a listener in `NotificationBuilder` to handle notification removal.
• Removed the `OnMailUpdated` method from `AppShellViewModel`, delegating notification management to the new event system.
• Updated `MailService` to send `MailReadStatusChanged` events when emails are marked as read.

This change improves the communication between components and enhances the notification management system.

* refactor: Remove comments

* Little cleanup.

---------

Co-authored-by: Burak Kaan Köse <bkaankose@outlook.com>
2025-07-26 12:51:53 +02:00
Maicol Battistini
c2bb07ff3d feat(preferences): Add email sync interval setting (#710)
* feat(preferences):  Add email sync interval setting

Introduced a new property `EmailSyncIntervalMinutes` in the `IPreferencesService` interface to allow users to configure the email synchronization interval in minutes. This feature enhances user control over email sync behavior.

• Updated `resources.json` to include translations for the new setting.
• Implemented the logic for the new property in `PreferencesService.cs`, with a default value of 3 minutes.
• Added binding and UI support in `AppPreferencesPageViewModel.cs` and `AppPreferencesPage.xaml` to allow users to modify the sync interval.
• Integrated the new setting into `ServerContext.cs` to dynamically adjust the synchronization timer based on user preferences.

This change improves the user experience by providing customizable email synchronization settings.

* Minimum interval and added an icon.

* Proper SetProperty usage.

* Making sure the minimum sync interval is 1 in the ServerContext.

* Making sure the minimum is applied to first trigger of the sync timer.

---------

Co-authored-by: Burak Kaan Köse <bkaankose@outlook.com>
2025-07-24 09:45:35 +02:00
Aleh Khantsevich
8cd7f68c30 fix save imap settings and progress ring. (#704)
Added notification that settings saved.
2025-07-07 19:28:56 +02:00
Aleh Khantsevich
3e889d8c08 Make height of single account navigation item smaller (#702)
* Make height of navigation item 50

* fix subtle and heights

* move spacing and margins

* make 52

* fix wrong heights
2025-07-02 23:41:41 +02:00
Aleh Khantsevich
a01395aed3 fix tab navigation for compose page (#695) 2025-06-21 13:35:42 +02:00
Aleh Khantsevich
7b3459abff Text input should update property on each changem instead of lost focus (#694) 2025-06-21 01:45:21 +02:00
Aleh Khantsevich
9a88f798fc fix animations (#689) 2025-06-21 01:40:45 +02:00
Maicol Battistini
256fd1cce2 feat: Enhanced sender avatars with gravatar and favicons integration (#685)
* feat: Enhanced sender avatars with gravatar and favicons integration

* chore: Remove unused known companies thumbnails

* feat(thumbnail): add IThumbnailService and refactor usage

- Introduced a new interface `IThumbnailService` for handling thumbnail-related functionalities.
- Registered `IThumbnailService` with its implementation `ThumbnailService` in the service container.
- Updated `NotificationBuilder` to use an instance of `IThumbnailService` instead of static methods.
- Refactored `ThumbnailService` from a static class to a regular class with instance methods and variables.
- Modified `ImagePreviewControl` to utilize the new `IThumbnailService` instance.
- Completed integration of `IThumbnailService` in the application by registering it in `App.xaml.cs`.

* style: Show favicons as squares

- Changed `hintCrop` in `NotificationBuilder` to `None` for app logo display.
- Added `FaviconSquircle`, `FaviconImage`, and `isFavicon` to `ImagePreviewControl` for favicon handling.
- Updated `UpdateInformation` method to manage favicon visibility.
- Introduced `GetBitmapImageAsync` for converting Base64 to Bitmap images.
- Enhanced XAML to include `FaviconSquircle` for improved UI appearance.

* refactor thumbnail service

* Removed old code and added clear method

* added prefetch function

* Change key from host to email

* Remove redundant code

* Test event

* Fixed an issue with the thumbnail updated event.

* Fix cutted favicons

* exclude some domain from favicons

* add yandex.ru

* fix buttons in settings

* remove prefetch method

* Added thumbnails propagation to mailRenderingPage

* Revert MailItemViewModel to object

* Remove redundant code

* spaces

* await load parameter added

* fix spaces

* fix case sensativity for mail list thumbnails

* change duckdns to google

* Some cleanup.

---------

Co-authored-by: Aleh Khantsevich <aleh.khantsevich@gmail.com>
Co-authored-by: Burak Kaan Köse <bkaankose@outlook.com>
2025-06-21 01:40:25 +02:00
Burak Kaan Köse
a8cb332232 Type fix. 2025-06-20 14:34:37 +02:00
Victor
89ea2b23a2 Replaced "Dismiss" button in notification popup with "Archive" button (#664)
* replaced "Dismiss" button in notification popup with "Archive" button

fixes https://github.com/bkaankose/Wino-Mail/issues/40

* Fixed incorrect build action for the archive icon.

---------

Co-authored-by: Burak Kaan Köse <bkaankose@outlook.com>
2025-06-15 15:27:39 +02:00
Aleh Khantsevich
9b214a66c8 Added new option to hide action labels in mail rendering page (#683)
* Added option to disable labels for mail actions

* Updated spacings and section title styles in settings

* Added translations
2025-06-15 15:17:57 +02:00
Aleh Khantsevich
4c4689ec8d Flyout styles and settings animations (#682)
* Refactor and enhance settings pages and solution structure

- Added transition effects to multiple pages for enhanced UI animations.
- Moved `AboutPage` and `PersonalizationPage` to settings folder.
- Put version into settings card instead of text.

* Fixed main logo in about page and changed version styles

* revert platforms

* Remove useless imprt

* Apply this animation globally

* Added resize transition for mail rendering page

* remove entrance transition from rendering page
2025-06-15 14:54:03 +02:00
Burak Kaan Köse
c4e561dee6 dotnet format refactorings. 2025-05-18 14:06:25 +02:00
Burak Kaan Köse
69bfe5b750 Fix calendar server startup. 2025-05-03 20:21:06 +02:00
Burak Kaan Köse
137b3dc2ea Merge branch 'main' of https://github.com/bkaankose/Wino-Mail 2025-05-03 19:08:36 +02:00
Burak Kaan Köse
ea5f879181 Fixed calendar slnx build. 2025-05-03 19:08:29 +02:00
Burak Kaan Köse
25d5f34f68 Version bump 2025-05-03 19:08:22 +02:00
Dinuru Seniya
c8a6df77ac Outlook Auth Fix (#653)
Issue: Account selector dialog pops up endlessly for Outlook/Live accounts. (Stored account not being correctly identified)

Fix: Ignore case differences, add null safety and remove whitespaces when retrieving stored accounts.
2025-05-02 12:12:45 +02:00
Burak Kaan Köse
7b6ac46b6a More informational message for different UPN and address for Outlook authenticator. 2025-04-26 12:25:34 +02:00
Burak Kaan Köse
d77c648d54 New Crowdin updates (#646)
* New translations resources.json (Romanian)

* New translations resources.json (French)

* New translations resources.json (Spanish)

* New translations resources.json (Bulgarian)

* New translations resources.json (Czech)

* New translations resources.json (German)

* New translations resources.json (Greek)

* New translations resources.json (Italian)

* New translations resources.json (Dutch)

* New translations resources.json (Polish)

* New translations resources.json (Slovak)

* New translations resources.json (Ukrainian)

* New translations resources.json (Chinese Simplified)

* New translations resources.json (Portuguese, Brazilian)
2025-04-26 11:04:03 +02:00
Burak Kaan Köse
c3f47c5fa1 Check account notification preferences after the synchronization. (#647) 2025-04-26 11:02:41 +02:00
Burak Kaan Köse
f37a51b46f Remove test code. 2025-04-26 10:51:14 +02:00
Burak Kaan Köse
9feb3f35c3 Synchronizer error factory implementation (#645)
* Added sync error factories for outlook and gmail.

* Implement ObjectCannotBeDeletedHandler for OutlookSynchronizer.

* Remove debug code.

* Implement del key to delete on mail list.

* Revert debug code.
2025-04-26 10:49:55 +02:00
Burak Kaan Köse
5b44cf03ce Don't report when printing is canceled. 2025-04-21 10:31:23 +02:00
Burak Kaan Köse
86a6382463 Max 1500 mails to download per-folder on initial sync for Gmail. 2025-04-21 10:15:42 +02:00
Burak Kaan Köse
df991a3829 Bump nugets. 2025-04-21 10:15:05 +02:00
Grigory
f243c86b50 build(nuget.config): correct nuget packageSources key name (#623) 2025-04-06 11:33:30 +02:00
Grigory
b77be0a5e9 build(Wino.Server.csproj): specify RuntimeIdentifiers (#621) 2025-04-06 11:33:08 +02:00
Burak Kaan Köse
83be587c1a Make sure there are no duplicate items for providers except Gmail when creating mails. 2025-04-04 23:55:50 +02:00
Burak Kaan Köse
c6048aea80 Make sure the requests are reflected to UI during synchronization. 2025-03-19 23:37:50 +01:00
Burak Kaan Köse
13b495b0f6 Fixed the Gmail sync identifier update issue and removed the batch message download. 2025-03-19 23:22:57 +01:00
Burak Kaan Köse
ac64c35efa Fix for another sequence contains error. 2025-03-19 22:15:28 +01:00
Burak Kaan Köse
127b58601f Remove missing isuread property. 2025-03-18 00:12:31 +01:00
Burak Kaan Köse
1f795b45e9 More visible unread items. 2025-03-18 00:10:45 +01:00
Burak Kaan Köse
d26e35ee9a Ctrl + A to select all mails. 2025-03-15 17:43:57 +01:00
Burak Kaan Köse
70e69e9dac Wino Calendar slnx 2025-03-15 15:23:26 +01:00
Burak Kaan Köse
3d88f4212d Merge branch 'main' of https://github.com/bkaankose/Wino-Mail 2025-03-15 15:22:43 +01:00
Burak Kaan Köse
ad90a9c8f3 Fix: Sequence contains no elements while downloading Gmail messages. 2025-03-15 15:22:01 +01:00
Aleh Khantsevich
b43176764b Trim all whitespaces, including \t for unsubscribe links (#599) 2025-03-06 22:34:05 +01:00
Burak Kaan Köse
77f24282e0 Fix incorrect visibility. 2025-03-01 19:43:32 +01:00
Burak Kaan Köse
533f1f1102 1.10.2 release notes. 2025-03-01 19:43:21 +01:00
Burak Kaan Köse
92c5d8bd44 New translations resources.json (Turkish) (#595) 2025-03-01 17:09:54 +01:00
Burak Kaan Köse
d754ecb486 New Crowdin updates (#594)
* New translations resources.json (Romanian)

* New translations resources.json (French)

* New translations resources.json (Spanish)

* New translations resources.json (Catalan)

* New translations resources.json (Czech)

* New translations resources.json (Danish)

* New translations resources.json (German)

* New translations resources.json (Greek)

* New translations resources.json (Finnish)

* New translations resources.json (Italian)

* New translations resources.json (Japanese)

* New translations resources.json (Dutch)

* New translations resources.json (Polish)

* New translations resources.json (Russian)

* New translations resources.json (Turkish)

* New translations resources.json (Ukrainian)

* New translations resources.json (Chinese Simplified)

* New translations resources.json (Galician)

* New translations resources.json (Portuguese, Brazilian)

* New translations resources.json (Indonesian)

* New translations resources.json (Lithuanian)
2025-03-01 17:05:04 +01:00
Burak Kaan Köse
b18987a95c Added ability to edit imap server configuration. (#593) 2025-03-01 16:53:05 +01:00
EzraWard
0daec61f31 Display app name on Win10 start tiles (#591) 2025-03-01 01:17:42 +01:00
Burak Kaan Köse
8ecf301eb8 Account colors + edit account details. (#592)
* Remove account rename dialog. Implement edit account details page.

* Remove unused folder definition.

* Adressing theming issues and adding reset button. Changing the UI a bit.

* Enable auto indent in initializer. Use service from the application.

* Adding color picker to acc setup dialog. Changing UI of edit acc details page.
2025-03-01 01:17:04 +01:00
Burak Kaan Köse
6080646e89 Don't crash on contact inserts. 2025-02-28 18:21:31 +01:00
Burak Kaan Köse
970a521b66 Pre-warmup on imap synchronizer interface. 2025-02-26 23:13:17 +01:00
Burak Kaan Köse
9b5a92f942 Changing delete logic. 2025-02-26 23:13:05 +01:00
Burak Kaan Köse
c4e0f13d67 Pre warmup trigger on synchronizer creation for imaps. 2025-02-26 23:12:01 +01:00
Burak Kaan Köse
b6821746d0 Locked busy scope to handle disconnections properly. 2025-02-26 23:11:49 +01:00
Burak Kaan Köse
b98fc91a99 Refactoring ImapClientPool. Implemented no-op timer and pre-warmup clients logic. Disabled protocol log per-account. 2025-02-26 23:11:16 +01:00
Burak Kaan Köse
bd7f7b867e Making sure missing draft folder is handling during draft creation. 2025-02-26 23:10:30 +01:00
Burak Kaan Köse
32a3fea8d7 Automatically append sent messages to sent folder for iCloud and Yahoo. 2025-02-26 22:57:08 +01:00
Burak Kaan Köse
3561beab1d Revert bump graph. 2025-02-26 22:18:25 +01:00
Burak Kaan Köse
1d1fd52cae Refactoring mail collection class. 2025-02-26 19:59:20 +01:00
Burak Kaan Köse
c4ba438150 Handling of generalException and some refactorings on batch executions. 2025-02-26 19:59:11 +01:00
Burak Kaan Köse
37f0ee08b1 Bump graph API. 2025-02-26 19:22:43 +01:00
Burak Kaan Köse
240b02c94e Fix gmail mail service not enabled error. 2025-02-26 19:04:38 +01:00
Burak Kaan Köse
e8142ff3df Download messages in ascending order. 2025-02-26 11:45:23 +01:00
283 changed files with 10083 additions and 7465 deletions

View File

@@ -1,65 +1,68 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally> <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageVersion Include="ColorHashSharp" Version="1.0.0" /> <PackageVersion Include="ColorHashSharp" Version="1.0.0" />
<PackageVersion Include="CommunityToolkit.Common" Version="8.4.0" /> <PackageVersion Include="CommunityToolkit.Common" Version="8.4.0" />
<PackageVersion Include="CommunityToolkit.Diagnostics" Version="8.4.0" /> <PackageVersion Include="CommunityToolkit.Diagnostics" Version="8.4.0" />
<PackageVersion Include="CommunityToolkit.Labs.Uwp.Controls.MarkdownTextBlock" Version="0.1.250206-build.2040" /> <PackageVersion Include="CommunityToolkit.Labs.Uwp.Controls.MarkdownTextBlock" Version="0.1.250206-build.2040" />
<PackageVersion Include="CommunityToolkit.Labs.Uwp.DependencyPropertyGenerator" Version="0.1.250206-build.2040" /> <PackageVersion Include="CommunityToolkit.Labs.Uwp.DependencyPropertyGenerator" Version="0.1.250206-build.2040" />
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0" /> <PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0" />
<PackageVersion Include="CommunityToolkit.Uwp.Animations" Version="8.2.250129-preview2" /> <PackageVersion Include="CommunityToolkit.Uwp.Animations" Version="8.2.250402" />
<PackageVersion Include="CommunityToolkit.Uwp.Behaviors" Version="8.2.250129-preview2" /> <PackageVersion Include="CommunityToolkit.Uwp.Behaviors" Version="8.2.250402" />
<PackageVersion Include="CommunityToolkit.Uwp.Controls.Segmented" Version="8.2.250129-preview2" /> <PackageVersion Include="CommunityToolkit.Uwp.Controls.Segmented" Version="8.2.250402" />
<PackageVersion Include="CommunityToolkit.Uwp.Controls.SettingsControls" Version="8.2.250129-preview2" /> <PackageVersion Include="CommunityToolkit.Uwp.Controls.SettingsControls" Version="8.2.250402" />
<PackageVersion Include="CommunityToolkit.Uwp.Controls.Sizers" Version="8.2.250129-preview2" /> <PackageVersion Include="CommunityToolkit.Uwp.Controls.Sizers" Version="8.2.250402" />
<PackageVersion Include="CommunityToolkit.Uwp.Controls.TabbedCommandBar" Version="8.2.250129-preview2" /> <PackageVersion Include="CommunityToolkit.Uwp.Controls.TabbedCommandBar" Version="8.2.250402" />
<PackageVersion Include="CommunityToolkit.Uwp.Controls.TokenizingTextBox" Version="8.2.250129-preview2" /> <PackageVersion Include="CommunityToolkit.Uwp.Controls.TokenizingTextBox" Version="8.2.250402" />
<PackageVersion Include="CommunityToolkit.Uwp.Extensions" Version="8.2.250129-preview2" /> <PackageVersion Include="CommunityToolkit.Uwp.Extensions" Version="8.2.250402" />
<PackageVersion Include="EmailValidation" Version="1.2.0" /> <PackageVersion Include="CommunityToolkit.Uwp.Controls.Primitives" Version="8.2.250129-preview2" />
<PackageVersion Include="HtmlAgilityPack" Version="1.11.72" /> <PackageVersion Include="EmailValidation" Version="1.3.0" />
<PackageVersion Include="Ical.Net" Version="4.3.1" /> <PackageVersion Include="gravatar-dotnet" Version="0.1.3" />
<PackageVersion Include="IsExternalInit" Version="1.0.3" /> <PackageVersion Include="HtmlAgilityPack" Version="1.12.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" /> <PackageVersion Include="Ical.Net" Version="4.3.1" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" /> <PackageVersion Include="IsExternalInit" Version="1.0.3" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.2" /> <PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.2" /> <PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" />
<PackageVersion Include="Microsoft.Graph" Version="5.69.0" /> <PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.4" />
<PackageVersion Include="Microsoft.Identity.Client" Version="4.68.0" /> <PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.4" />
<PackageVersion Include="Microsoft.Identity.Client.Broker" Version="4.68.0" /> <PackageVersion Include="Microsoft.Graph" Version="5.75.0" />
<PackageVersion Include="Microsoft.Identity.Client.Extensions.Msal" Version="4.68.0" /> <PackageVersion Include="Microsoft.Identity.Client" Version="4.70.1" />
<PackageVersion Include="Microsoft.NETCore.UniversalWindowsPlatform" Version="6.2.14" /> <PackageVersion Include="Microsoft.Identity.Client.Broker" Version="4.70.1" />
<PackageVersion Include="Microsoft.UI.Xaml" Version="2.8.7" /> <PackageVersion Include="Microsoft.Identity.Client.Extensions.Msal" Version="4.70.1" />
<PackageVersion Include="Microsoft.Xaml.Behaviors.Uwp.Managed" Version="3.0.0" /> <PackageVersion Include="Microsoft.NETCore.UniversalWindowsPlatform" Version="6.2.14" />
<PackageVersion Include="MimeKit" Version="4.10.0" /> <PackageVersion Include="Microsoft.UI.Xaml" Version="2.8.7" />
<PackageVersion Include="morelinq" Version="4.4.0" /> <PackageVersion Include="Microsoft.Xaml.Behaviors.Uwp.Managed" Version="3.0.0" />
<PackageVersion Include="Nito.AsyncEx" Version="5.1.2" /> <PackageVersion Include="MimeKit" Version="4.11.0" />
<PackageVersion Include="Nito.AsyncEx.Tasks" Version="5.1.2" /> <PackageVersion Include="morelinq" Version="4.4.0" />
<PackageVersion Include="NodaTime" Version="3.2.1" /> <PackageVersion Include="Nito.AsyncEx" Version="5.1.2" />
<PackageVersion Include="Serilog" Version="4.2.0" /> <PackageVersion Include="Nito.AsyncEx.Tasks" Version="5.1.2" />
<PackageVersion Include="Serilog.Exceptions" Version="8.4.0" /> <PackageVersion Include="NodaTime" Version="3.2.2" />
<PackageVersion Include="Serilog.Sinks.Debug" Version="3.0.0" /> <PackageVersion Include="Sentry.Serilog" Version="5.12.0" />
<PackageVersion Include="Serilog.Sinks.File" Version="6.0.0" /> <PackageVersion Include="Serilog" Version="4.2.0" />
<PackageVersion Include="Serilog.Sinks.ApplicationInsights" Version="4.0.0" /> <PackageVersion Include="Serilog.Exceptions" Version="8.4.0" />
<PackageVersion Include="SkiaSharp" Version="3.116.1" /> <PackageVersion Include="Serilog.Sinks.Debug" Version="3.0.0" />
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" /> <PackageVersion Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageVersion Include="SqlKata" Version="4.0.1" /> <PackageVersion Include="Serilog.Sinks.ApplicationInsights" Version="4.0.0" />
<PackageVersion Include="System.Private.Uri" Version="4.3.2" /> <PackageVersion Include="SkiaSharp" Version="3.116.1" />
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.2" /> <PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
<PackageVersion Include="System.Text.Json" Version="9.0.2" /> <PackageVersion Include="SqlKata" Version="4.0.1" />
<PackageVersion Include="Win2D.uwp" Version="1.28.2" /> <PackageVersion Include="System.Private.Uri" Version="4.3.2" />
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.2.0" /> <PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.4" />
<PackageVersion Include="CommunityToolkit.WinUI.Notifications" Version="7.1.2" /> <PackageVersion Include="System.Text.Json" Version="9.0.4" />
<PackageVersion Include="Google.Apis.Auth" Version="1.69.0" /> <PackageVersion Include="Win2D.uwp" Version="1.28.2" />
<PackageVersion Include="Google.Apis.Calendar.v3" Version="1.69.0.3667" /> <PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.0" />
<PackageVersion Include="Google.Apis.Gmail.v1" Version="1.68.0.3427" /> <PackageVersion Include="CommunityToolkit.WinUI.Notifications" Version="7.1.2" />
<PackageVersion Include="Google.Apis.PeopleService.v1" Version="1.68.0.3359" /> <PackageVersion Include="Google.Apis.Auth" Version="1.69.0" />
<PackageVersion Include="HtmlKit" Version="1.2.0" /> <PackageVersion Include="Google.Apis.Calendar.v3" Version="1.69.0.3667" />
<PackageVersion Include="MailKit" Version="4.10.0" /> <PackageVersion Include="Google.Apis.Gmail.v1" Version="1.68.0.3427" />
<PackageVersion Include="TimePeriodLibrary.NET" Version="2.1.5" /> <PackageVersion Include="Google.Apis.PeopleService.v1" Version="1.68.0.3359" />
<PackageVersion Include="System.Reactive" Version="6.0.1" /> <PackageVersion Include="HtmlKit" Version="1.2.0" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.2" /> <PackageVersion Include="MailKit" Version="4.11.0" />
<PackageVersion Include="System.Text.Encodings.Web" Version="9.0.2" /> <PackageVersion Include="TimePeriodLibrary.NET" Version="2.1.6" />
</ItemGroup> <PackageVersion Include="System.Reactive" Version="6.0.1" />
</Project> <PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.4" />
<PackageVersion Include="System.Text.Encodings.Web" Version="9.0.4" />
</ItemGroup>
</Project>

View File

@@ -67,7 +67,8 @@ public class OutlookAuthenticator : BaseAuthenticator, IOutlookAuthenticator
{ {
await EnsureTokenCacheAttachedAsync(); await EnsureTokenCacheAttachedAsync();
var storedAccount = (await _publicClientApplication.GetAccountsAsync()).FirstOrDefault(a => a.Username == account.Address); var storedAccount = (await _publicClientApplication.GetAccountsAsync()).FirstOrDefault(
a => string.Equals(a.Username?.Trim(), account.Address?.Trim(), StringComparison.OrdinalIgnoreCase));
if (storedAccount == null) if (storedAccount == null)
return await GenerateTokenInformationAsync(account); return await GenerateTokenInformationAsync(account);
@@ -107,7 +108,7 @@ public class OutlookAuthenticator : BaseAuthenticator, IOutlookAuthenticator
if (account?.Address != null && !account.Address.Equals(authResult.Account.Username, StringComparison.OrdinalIgnoreCase)) if (account?.Address != null && !account.Address.Equals(authResult.Account.Username, StringComparison.OrdinalIgnoreCase))
{ {
throw new AuthenticationException("Authenticated address does not match with your account address."); throw new AuthenticationException("Authenticated address does not match with your account address. If you are signing with a Office365, it is not officially supported yet.");
} }
return new TokenInformationEx(authResult.AccessToken, authResult.Account.Username); return new TokenInformationEx(authResult.AccessToken, authResult.Account.Username);

View File

@@ -9,11 +9,12 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="CommunityToolkit.Diagnostics" /> <PackageReference Include="CommunityToolkit.Diagnostics" />
<PackageReference Include="CommunityToolkit.Mvvm" /> <PackageReference Include="CommunityToolkit.Mvvm" />
<PackageReference Include="Google.Apis.Auth" /> <PackageReference Include="Google.Apis.Auth" />
<PackageReference Include="Microsoft.Identity.Client" /> <PackageReference Include="Microsoft.Identity.Client" />
<PackageReference Include="Microsoft.Identity.Client.Broker" /> <PackageReference Include="Microsoft.Identity.Client.Broker" />
<PackageReference Include="Microsoft.Identity.Client.Extensions.Msal" /> <PackageReference Include="Microsoft.Identity.Client.Extensions.Msal" />
<PackageReference Include="Sentry.Serilog" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Wino.Core.Domain\Wino.Core.Domain.csproj" /> <ProjectReference Include="..\Wino.Core.Domain\Wino.Core.Domain.csproj" />

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -1,90 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap rescap">
<Identity
Name="58272BurakKSE.WinoCalendar"
Publisher="CN=51FBDAF3-E212-4149-89A2-A2636B3BC911"
Version="1.0.0.0" />
<Properties>
<DisplayName>Wino Calendar</DisplayName>
<PublisherDisplayName>Burak KÖSE</PublisherDisplayName>
<Logo>Images\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14393.0" MaxVersionTested="10.0.14393.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
</Resources>
<Applications>
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="$targetentrypoint$">
<uap:VisualElements
DisplayName="Wino Calendar"
Description="Wino.Calendar.Packaging"
BackgroundColor="transparent"
Square150x150Logo="Images\Square150x150Logo.png"
Square44x44Logo="Images\Square44x44Logo.png">
<uap:DefaultTile Wide310x150Logo="Images\Wide310x150Logo.png" />
<uap:SplashScreen Image="Images\SplashScreen.png" />
</uap:VisualElements>
<Extensions>
<!-- Registration of full trust backend application. -->
<uap:Extension Category="windows.appService">
<uap:AppService Name="WinoInteropService" />
</uap:Extension>
<!-- Protocol activation: Google OAuth -->
<uap:Extension Category="windows.protocol">
<uap:Protocol Name="google.pw.oauth2">
<uap:DisplayName>Wino Google Authentication Protocol</uap:DisplayName>
</uap:Protocol>
</uap:Extension>
<!-- Protocol activation: Launch UWP app from Full Trust Process -->
<uap:Extension Category="windows.protocol">
<uap:Protocol Name="wino.calendar.launch">
<uap:DisplayName>Wino Calendara Launcher Protocol</uap:DisplayName>
</uap:Protocol>
</uap:Extension>
<!-- Startup Task -->
<uap5:Extension
Category="windows.startupTask"
Executable="Wino.Server\Wino.Server.exe"
EntryPoint="Windows.FullTrustApplication">
<uap5:StartupTask
TaskId="WinoServer"
Enabled="false"
DisplayName="Wino Mail" />
</uap5:Extension>
<desktop:Extension Category="windows.fullTrustProcess" Executable="Wino.Server\Wino.Server.exe">
<desktop:FullTrustProcess>
<desktop:ParameterGroup GroupId="WinoServer" Parameters="Calendar" />
</desktop:FullTrustProcess>
</desktop:Extension>
</Extensions>
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClient" />
<rescap:Capability Name="runFullTrust" />
<rescap:Capability Name="confirmAppClose" />
</Capabilities>
</Package>

View File

@@ -1,77 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '15.0'">
<VisualStudioVersion>15.0</VisualStudioVersion>
</PropertyGroup>
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x86">
<Configuration>Debug</Configuration>
<Platform>x86</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x86">
<Configuration>Release</Configuration>
<Platform>x86</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|AnyCPU">
<Configuration>Debug</Configuration>
<Platform>AnyCPU</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|AnyCPU">
<Configuration>Release</Configuration>
<Platform>AnyCPU</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup>
<WapProjPath Condition="'$(WapProjPath)'==''">$(MSBuildExtensionsPath)\Microsoft\DesktopBridge\</WapProjPath>
</PropertyGroup>
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.props" />
<PropertyGroup>
<ProjectGuid>7485b18c-f5ab-4abe-ba7f-05b6623c67c8</ProjectGuid>
<TargetPlatformVersion>10.0.22621.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<DefaultLanguage>en-US</DefaultLanguage>
<AppxPackageSigningEnabled>false</AppxPackageSigningEnabled>
<NoWarn>$(NoWarn);NU1702</NoWarn>
<EntryPointProjectUniqueName>..\Wino.Calendar\Wino.Calendar.csproj</EntryPointProjectUniqueName>
<GenerateTemporaryStoreCertificate>True</GenerateTemporaryStoreCertificate>
</PropertyGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
</ItemGroup>
<ItemGroup>
<Content Include="Images\SplashScreen.scale-200.png" />
<Content Include="Images\LockScreenLogo.scale-200.png" />
<Content Include="Images\Square150x150Logo.scale-200.png" />
<Content Include="Images\Square44x44Logo.scale-200.png" />
<Content Include="Images\Square44x44Logo.targetsize-24_altform-unplated.png" />
<Content Include="Images\StoreLogo.png" />
<Content Include="Images\Wide310x150Logo.scale-200.png" />
<None Include="Package.StoreAssociation.xml" />
</ItemGroup>
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.targets" />
<ItemGroup>
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.1742" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Wino.Calendar\Wino.Calendar.csproj" />
<ProjectReference Include="..\Wino.Server\Wino.Server.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,48 +1,37 @@
using System.Threading.Tasks; using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Messaging;
using Wino.Calendar.ViewModels.Interfaces; using Wino.Calendar.ViewModels.Interfaces;
using Wino.Core.Domain;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.Navigation; using Wino.Core.Domain.Models.Navigation;
using Wino.Core.ViewModels; using Wino.Core.ViewModels;
using Wino.Mail.ViewModels.Data; using Wino.Mail.ViewModels.Data;
using Wino.Messaging.UI; using Wino.Messaging.Client.Navigation;
namespace Wino.Calendar.ViewModels namespace Wino.Calendar.ViewModels;
public partial class AccountDetailsPageViewModel : CalendarBaseViewModel
{ {
public partial class AccountDetailsPageViewModel : CalendarBaseViewModel private readonly IAccountService _accountService;
public AccountProviderDetailViewModel Account { get; private set; }
public ICalendarDialogService CalendarDialogService { get; }
public IAccountCalendarStateService AccountCalendarStateService { get; }
public AccountDetailsPageViewModel(ICalendarDialogService calendarDialogService, IAccountService accountService, IAccountCalendarStateService accountCalendarStateService)
{ {
private readonly IAccountService _accountService; CalendarDialogService = calendarDialogService;
_accountService = accountService;
AccountCalendarStateService = accountCalendarStateService;
}
public AccountProviderDetailViewModel Account { get; private set; } [RelayCommand]
public ICalendarDialogService CalendarDialogService { get; } private void EditAccountDetails()
public IAccountCalendarStateService AccountCalendarStateService { get; } => Messenger.Send(new BreadcrumbNavigationRequested(Translator.SettingsEditAccountDetails_Title, WinoPage.EditAccountDetailsPage, Account));
public AccountDetailsPageViewModel(ICalendarDialogService calendarDialogService, IAccountService accountService, IAccountCalendarStateService accountCalendarStateService) public override void OnNavigatedTo(NavigationMode mode, object parameters)
{ {
CalendarDialogService = calendarDialogService; base.OnNavigatedTo(mode, parameters);
_accountService = accountService;
AccountCalendarStateService = accountCalendarStateService;
}
[RelayCommand]
private async Task RenameAccount()
{
if (Account == null)
return;
var updatedAccount = await CalendarDialogService.ShowEditAccountDialogAsync(Account.Account);
if (updatedAccount != null)
{
await _accountService.UpdateAccountAsync(updatedAccount);
ReportUIChange(new AccountUpdatedMessage(updatedAccount));
}
}
public override void OnNavigatedTo(NavigationMode mode, object parameters)
{
base.OnNavigatedTo(mode, parameters);
}
} }
} }

View File

@@ -13,135 +13,134 @@ using Wino.Core.Domain.Models.Synchronization;
using Wino.Core.ViewModels; using Wino.Core.ViewModels;
using Wino.Messaging.Server; using Wino.Messaging.Server;
namespace Wino.Calendar.ViewModels namespace Wino.Calendar.ViewModels;
public partial class AccountManagementViewModel : AccountManagementPageViewModelBase
{ {
public partial class AccountManagementViewModel : AccountManagementPageViewModelBase private readonly IProviderService _providerService;
public AccountManagementViewModel(ICalendarDialogService dialogService,
IWinoServerConnectionManager winoServerConnectionManager,
INavigationService navigationService,
IAccountService accountService,
IProviderService providerService,
IStoreManagementService storeManagementService,
IAuthenticationProvider authenticationProvider,
IPreferencesService preferencesService) : base(dialogService, winoServerConnectionManager, navigationService, accountService, providerService, storeManagementService, authenticationProvider, preferencesService)
{ {
private readonly IProviderService _providerService; CalendarDialogService = dialogService;
_providerService = providerService;
}
public AccountManagementViewModel(ICalendarDialogService dialogService, public ICalendarDialogService CalendarDialogService { get; }
IWinoServerConnectionManager winoServerConnectionManager,
INavigationService navigationService, public override async void OnNavigatedTo(NavigationMode mode, object parameters)
IAccountService accountService, {
IProviderService providerService, base.OnNavigatedTo(mode, parameters);
IStoreManagementService storeManagementService,
IAuthenticationProvider authenticationProvider, await InitializeAccountsAsync();
IPreferencesService preferencesService) : base(dialogService, winoServerConnectionManager, navigationService, accountService, providerService, storeManagementService, authenticationProvider, preferencesService) }
public override async Task InitializeAccountsAsync()
{
Accounts.Clear();
var accounts = await AccountService.GetAccountsAsync().ConfigureAwait(false);
await ExecuteUIThread(() =>
{ {
CalendarDialogService = dialogService; foreach (var account in accounts)
_providerService = providerService;
}
public ICalendarDialogService CalendarDialogService { get; }
public override async void OnNavigatedTo(NavigationMode mode, object parameters)
{
base.OnNavigatedTo(mode, parameters);
await InitializeAccountsAsync();
}
public override async Task InitializeAccountsAsync()
{
Accounts.Clear();
var accounts = await AccountService.GetAccountsAsync().ConfigureAwait(false);
await ExecuteUIThread(() =>
{ {
foreach (var account in accounts) var accountDetails = GetAccountProviderDetails(account);
{
var accountDetails = GetAccountProviderDetails(account);
Accounts.Add(accountDetails); Accounts.Add(accountDetails);
}
});
await ManageStorePurchasesAsync().ConfigureAwait(false);
}
[RelayCommand]
private async Task AddNewAccountAsync()
{
if (IsAccountCreationBlocked)
{
var isPurchaseClicked = await DialogService.ShowConfirmationDialogAsync(Translator.DialogMessage_AccountLimitMessage, Translator.DialogMessage_AccountLimitTitle, Translator.Buttons_Purchase);
if (!isPurchaseClicked) return;
await PurchaseUnlimitedAccountAsync();
return;
} }
});
var availableProviders = _providerService.GetAvailableProviders(); await ManageStorePurchasesAsync().ConfigureAwait(false);
}
var accountCreationDialogResult = await DialogService.ShowAccountProviderSelectionDialogAsync(availableProviders); [RelayCommand]
private async Task AddNewAccountAsync()
{
if (IsAccountCreationBlocked)
{
var isPurchaseClicked = await DialogService.ShowConfirmationDialogAsync(Translator.DialogMessage_AccountLimitMessage, Translator.DialogMessage_AccountLimitTitle, Translator.Buttons_Purchase);
if (accountCreationDialogResult == null) return; if (!isPurchaseClicked) return;
var accountCreationCancellationTokenSource = new CancellationTokenSource(); await PurchaseUnlimitedAccountAsync();
var accountCreationDialog = CalendarDialogService.GetAccountCreationDialog(accountCreationDialogResult);
accountCreationDialog.ShowDialog(accountCreationCancellationTokenSource); return;
accountCreationDialog.State = AccountCreationDialogState.SigningIn; }
// For OAuth authentications, we just generate token and assign it to the MailAccount. var availableProviders = _providerService.GetAvailableProviders();
var createdAccount = new MailAccount() var accountCreationDialogResult = await DialogService.ShowAccountProviderSelectionDialogAsync(availableProviders);
{
ProviderType = accountCreationDialogResult.ProviderType,
Name = accountCreationDialogResult.AccountName,
Id = Guid.NewGuid()
};
var tokenInformationResponse = await WinoServerConnectionManager if (accountCreationDialogResult == null) return;
.GetResponseAsync<TokenInformationEx, AuthorizationRequested>(new AuthorizationRequested(accountCreationDialogResult.ProviderType,
createdAccount,
createdAccount.ProviderType == MailProviderType.Gmail), accountCreationCancellationTokenSource.Token);
if (accountCreationDialog.State == AccountCreationDialogState.Canceled) var accountCreationCancellationTokenSource = new CancellationTokenSource();
throw new AccountSetupCanceledException(); var accountCreationDialog = CalendarDialogService.GetAccountCreationDialog(accountCreationDialogResult);
tokenInformationResponse.ThrowIfFailed(); await accountCreationDialog.ShowDialogAsync(accountCreationCancellationTokenSource);
await Task.Delay(500);
await AccountService.CreateAccountAsync(createdAccount, null); // For OAuth authentications, we just generate token and assign it to the MailAccount.
// Sync profile information if supported. var createdAccount = new MailAccount()
if (createdAccount.IsProfileInfoSyncSupported) {
{ ProviderType = accountCreationDialogResult.ProviderType,
// Start profile information synchronization. Name = accountCreationDialogResult.AccountName,
// It's only available for Outlook and Gmail synchronizers. Id = Guid.NewGuid()
};
var profileSyncOptions = new MailSynchronizationOptions() var tokenInformationResponse = await WinoServerConnectionManager
{ .GetResponseAsync<TokenInformationEx, AuthorizationRequested>(new AuthorizationRequested(accountCreationDialogResult.ProviderType,
AccountId = createdAccount.Id, createdAccount,
Type = MailSynchronizationType.UpdateProfile createdAccount.ProviderType == MailProviderType.Gmail), accountCreationCancellationTokenSource.Token);
};
var profileSynchronizationResponse = await WinoServerConnectionManager.GetResponseAsync<MailSynchronizationResult, NewMailSynchronizationRequested>(new NewMailSynchronizationRequested(profileSyncOptions, SynchronizationSource.Client)); if (accountCreationDialog.State == AccountCreationDialogState.Canceled)
throw new AccountSetupCanceledException();
var profileSynchronizationResult = profileSynchronizationResponse.Data; tokenInformationResponse.ThrowIfFailed();
if (profileSynchronizationResult.CompletedState != SynchronizationCompletedState.Success) await AccountService.CreateAccountAsync(createdAccount, null);
throw new Exception(Translator.Exception_FailedToSynchronizeProfileInformation);
createdAccount.SenderName = profileSynchronizationResult.ProfileInformation.SenderName; // Sync profile information if supported.
createdAccount.Base64ProfilePictureData = profileSynchronizationResult.ProfileInformation.Base64ProfilePictureData; if (createdAccount.IsProfileInfoSyncSupported)
{
// Start profile information synchronization.
// It's only available for Outlook and Gmail synchronizers.
await AccountService.UpdateProfileInformationAsync(createdAccount.Id, profileSynchronizationResult.ProfileInformation); var profileSyncOptions = new MailSynchronizationOptions()
}
accountCreationDialog.State = AccountCreationDialogState.FetchingEvents;
// Start synchronizing events.
var synchronizationOptions = new CalendarSynchronizationOptions()
{ {
AccountId = createdAccount.Id, AccountId = createdAccount.Id,
Type = CalendarSynchronizationType.CalendarMetadata Type = MailSynchronizationType.UpdateProfile
}; };
var synchronizationResponse = await WinoServerConnectionManager.GetResponseAsync<CalendarSynchronizationResult, NewCalendarSynchronizationRequested>(new NewCalendarSynchronizationRequested(synchronizationOptions, SynchronizationSource.Client)); var profileSynchronizationResponse = await WinoServerConnectionManager.GetResponseAsync<MailSynchronizationResult, NewMailSynchronizationRequested>(new NewMailSynchronizationRequested(profileSyncOptions, SynchronizationSource.Client));
var profileSynchronizationResult = profileSynchronizationResponse.Data;
if (profileSynchronizationResult.CompletedState != SynchronizationCompletedState.Success)
throw new Exception(Translator.Exception_FailedToSynchronizeProfileInformation);
createdAccount.SenderName = profileSynchronizationResult.ProfileInformation.SenderName;
createdAccount.Base64ProfilePictureData = profileSynchronizationResult.ProfileInformation.Base64ProfilePictureData;
await AccountService.UpdateProfileInformationAsync(createdAccount.Id, profileSynchronizationResult.ProfileInformation);
} }
accountCreationDialog.State = AccountCreationDialogState.FetchingEvents;
// Start synchronizing events.
var synchronizationOptions = new CalendarSynchronizationOptions()
{
AccountId = createdAccount.Id,
Type = CalendarSynchronizationType.CalendarMetadata
};
var synchronizationResponse = await WinoServerConnectionManager.GetResponseAsync<CalendarSynchronizationResult, NewCalendarSynchronizationRequested>(new NewCalendarSynchronizationRequested(synchronizationOptions, SynchronizationSource.Client));
} }
} }

View File

@@ -21,347 +21,346 @@ using Wino.Messaging.Client.Calendar;
using Wino.Messaging.Client.Navigation; using Wino.Messaging.Client.Navigation;
using Wino.Messaging.Server; using Wino.Messaging.Server;
namespace Wino.Calendar.ViewModels namespace Wino.Calendar.ViewModels;
public partial class AppShellViewModel : CalendarBaseViewModel,
IRecipient<VisibleDateRangeChangedMessage>,
IRecipient<CalendarEnableStatusChangedMessage>,
IRecipient<NavigateManageAccountsRequested>,
IRecipient<CalendarDisplayTypeChangedMessage>,
IRecipient<DetailsPageStateChangedMessage>
{ {
public partial class AppShellViewModel : CalendarBaseViewModel, public IPreferencesService PreferencesService { get; }
IRecipient<VisibleDateRangeChangedMessage>, public IStatePersistanceService StatePersistenceService { get; }
IRecipient<CalendarEnableStatusChangedMessage>, public IAccountCalendarStateService AccountCalendarStateService { get; }
IRecipient<NavigateManageAccountsRequested>, public INavigationService NavigationService { get; }
IRecipient<CalendarDisplayTypeChangedMessage>, public IWinoServerConnectionManager ServerConnectionManager { get; }
IRecipient<DetailsPageStateChangedMessage>
[ObservableProperty]
private bool _isEventDetailsPageActive;
[ObservableProperty]
private int _selectedMenuItemIndex = -1;
[ObservableProperty]
private bool isCalendarEnabled;
/// <summary>
/// Gets or sets the active connection status of the Wino server.
/// </summary>
[ObservableProperty]
private WinoServerConnectionStatus activeConnectionStatus;
/// <summary>
/// Gets or sets the display date of the calendar.
/// </summary>
[ObservableProperty]
private DateTimeOffset _displayDate;
/// <summary>
/// Gets or sets the highlighted range in the CalendarView and displayed date range in FlipView.
/// </summary>
[ObservableProperty]
private DateRange highlightedDateRange;
[ObservableProperty]
private ObservableRangeCollection<string> dateNavigationHeaderItems = [];
[ObservableProperty]
private int _selectedDateNavigationHeaderIndex;
public bool IsVerticalCalendar => StatePersistenceService.CalendarDisplayType == CalendarDisplayType.Month;
// For updating account calendars asynchronously.
private SemaphoreSlim _accountCalendarUpdateSemaphoreSlim = new(1);
public AppShellViewModel(IPreferencesService preferencesService,
IStatePersistanceService statePersistanceService,
IAccountService accountService,
ICalendarService calendarService,
IAccountCalendarStateService accountCalendarStateService,
INavigationService navigationService,
IWinoServerConnectionManager serverConnectionManager)
{ {
public IPreferencesService PreferencesService { get; } _accountService = accountService;
public IStatePersistanceService StatePersistenceService { get; } _calendarService = calendarService;
public IAccountCalendarStateService AccountCalendarStateService { get; }
public INavigationService NavigationService { get; }
public IWinoServerConnectionManager ServerConnectionManager { get; }
[ObservableProperty] AccountCalendarStateService = accountCalendarStateService;
private bool _isEventDetailsPageActive; AccountCalendarStateService.AccountCalendarSelectionStateChanged += UpdateAccountCalendarRequested;
AccountCalendarStateService.CollectiveAccountGroupSelectionStateChanged += AccountCalendarStateCollectivelyChanged;
[ObservableProperty] NavigationService = navigationService;
private int _selectedMenuItemIndex = -1; ServerConnectionManager = serverConnectionManager;
PreferencesService = preferencesService;
[ObservableProperty] StatePersistenceService = statePersistanceService;
private bool isCalendarEnabled; StatePersistenceService.StatePropertyChanged += PrefefencesChanged;
}
/// <summary> private void SelectedCalendarItemsChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
/// Gets or sets the active connection status of the Wino server. {
/// </summary> throw new NotImplementedException();
[ObservableProperty] }
private WinoServerConnectionStatus activeConnectionStatus;
/// <summary> private void PrefefencesChanged(object sender, string e)
/// Gets or sets the display date of the calendar. {
/// </summary> if (e == nameof(StatePersistenceService.CalendarDisplayType))
[ObservableProperty]
private DateTimeOffset _displayDate;
/// <summary>
/// Gets or sets the highlighted range in the CalendarView and displayed date range in FlipView.
/// </summary>
[ObservableProperty]
private DateRange highlightedDateRange;
[ObservableProperty]
private ObservableRangeCollection<string> dateNavigationHeaderItems = [];
[ObservableProperty]
private int _selectedDateNavigationHeaderIndex;
public bool IsVerticalCalendar => StatePersistenceService.CalendarDisplayType == CalendarDisplayType.Month;
// For updating account calendars asynchronously.
private SemaphoreSlim _accountCalendarUpdateSemaphoreSlim = new(1);
public AppShellViewModel(IPreferencesService preferencesService,
IStatePersistanceService statePersistanceService,
IAccountService accountService,
ICalendarService calendarService,
IAccountCalendarStateService accountCalendarStateService,
INavigationService navigationService,
IWinoServerConnectionManager serverConnectionManager)
{ {
_accountService = accountService; Messenger.Send(new CalendarDisplayTypeChangedMessage(StatePersistenceService.CalendarDisplayType));
_calendarService = calendarService;
AccountCalendarStateService = accountCalendarStateService;
AccountCalendarStateService.AccountCalendarSelectionStateChanged += UpdateAccountCalendarRequested;
AccountCalendarStateService.CollectiveAccountGroupSelectionStateChanged += AccountCalendarStateCollectivelyChanged;
NavigationService = navigationService; // Change the calendar.
ServerConnectionManager = serverConnectionManager; DateClicked(new CalendarViewDayClickedEventArgs(GetDisplayTypeSwitchDate()));
PreferencesService = preferencesService;
StatePersistenceService = statePersistanceService;
StatePersistenceService.StatePropertyChanged += PrefefencesChanged;
} }
}
private void SelectedCalendarItemsChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) public override async void OnNavigatedTo(NavigationMode mode, object parameters)
{ {
throw new NotImplementedException(); base.OnNavigatedTo(mode, parameters);
}
private void PrefefencesChanged(object sender, string e) UpdateDateNavigationHeaderItems();
await InitializeAccountCalendarsAsync();
TodayClicked();
}
private async void AccountCalendarStateCollectivelyChanged(object sender, GroupedAccountCalendarViewModel e)
{
// When using three-state checkbox, multiple accounts will be selected/unselected at the same time.
// Reporting all these changes one by one to the UI is not efficient and may cause problems in the future.
// Update all calendar states at once.
try
{ {
if (e == nameof(StatePersistenceService.CalendarDisplayType)) await _accountCalendarUpdateSemaphoreSlim.WaitAsync();
foreach (var calendar in e.AccountCalendars)
{ {
Messenger.Send(new CalendarDisplayTypeChangedMessage(StatePersistenceService.CalendarDisplayType)); await _calendarService.UpdateAccountCalendarAsync(calendar.AccountCalendar).ConfigureAwait(false);
// Change the calendar.
DateClicked(new CalendarViewDayClickedEventArgs(GetDisplayTypeSwitchDate()));
} }
} }
catch (Exception ex)
public override async void OnNavigatedTo(NavigationMode mode, object parameters)
{ {
base.OnNavigatedTo(mode, parameters); Log.Error(ex, "Error while waiting for account calendar update semaphore.");
UpdateDateNavigationHeaderItems();
await InitializeAccountCalendarsAsync();
TodayClicked();
} }
finally
private async void AccountCalendarStateCollectivelyChanged(object sender, GroupedAccountCalendarViewModel e)
{ {
// When using three-state checkbox, multiple accounts will be selected/unselected at the same time. _accountCalendarUpdateSemaphoreSlim.Release();
// Reporting all these changes one by one to the UI is not efficient and may cause problems in the future.
// Update all calendar states at once.
try
{
await _accountCalendarUpdateSemaphoreSlim.WaitAsync();
foreach (var calendar in e.AccountCalendars)
{
await _calendarService.UpdateAccountCalendarAsync(calendar.AccountCalendar).ConfigureAwait(false);
}
}
catch (Exception ex)
{
Log.Error(ex, "Error while waiting for account calendar update semaphore.");
}
finally
{
_accountCalendarUpdateSemaphoreSlim.Release();
}
} }
}
private async void UpdateAccountCalendarRequested(object sender, AccountCalendarViewModel e) private async void UpdateAccountCalendarRequested(object sender, AccountCalendarViewModel e)
=> await _calendarService.UpdateAccountCalendarAsync(e.AccountCalendar).ConfigureAwait(false); => await _calendarService.UpdateAccountCalendarAsync(e.AccountCalendar).ConfigureAwait(false);
private async Task InitializeAccountCalendarsAsync() private async Task InitializeAccountCalendarsAsync()
{
await Dispatcher.ExecuteOnUIThread(() => AccountCalendarStateService.ClearGroupedAccountCalendar());
var accounts = await _accountService.GetAccountsAsync().ConfigureAwait(false);
foreach (var account in accounts)
{ {
await Dispatcher.ExecuteOnUIThread(() => AccountCalendarStateService.ClearGroupedAccountCalendar()); var accountCalendars = await _calendarService.GetAccountCalendarsAsync(account.Id).ConfigureAwait(false);
var calendarViewModels = new List<AccountCalendarViewModel>();
var accounts = await _accountService.GetAccountsAsync().ConfigureAwait(false); foreach (var calendar in accountCalendars)
foreach (var account in accounts)
{ {
var accountCalendars = await _calendarService.GetAccountCalendarsAsync(account.Id).ConfigureAwait(false); var calendarViewModel = new AccountCalendarViewModel(account, calendar);
var calendarViewModels = new List<AccountCalendarViewModel>();
foreach (var calendar in accountCalendars) calendarViewModels.Add(calendarViewModel);
{
var calendarViewModel = new AccountCalendarViewModel(account, calendar);
calendarViewModels.Add(calendarViewModel);
}
var groupedAccountCalendarViewModel = new GroupedAccountCalendarViewModel(account, calendarViewModels);
await Dispatcher.ExecuteOnUIThread(() =>
{
AccountCalendarStateService.AddGroupedAccountCalendar(groupedAccountCalendarViewModel);
});
}
}
private void ForceNavigateCalendarDate()
{
if (SelectedMenuItemIndex == -1)
{
var args = new CalendarPageNavigationArgs()
{
NavigationDate = _navigationDate ?? DateTime.Now.Date
};
// Already on calendar. Just navigate.
NavigationService.Navigate(WinoPage.CalendarPage, args);
_navigationDate = null;
}
else
{
SelectedMenuItemIndex = -1;
}
}
partial void OnSelectedMenuItemIndexChanged(int oldValue, int newValue)
{
switch (newValue)
{
case -1:
ForceNavigateCalendarDate();
break;
case 0:
NavigationService.Navigate(WinoPage.ManageAccountsPage);
break;
case 1:
NavigationService.Navigate(WinoPage.SettingsPage);
break;
default:
break;
}
}
[RelayCommand]
private async Task Sync()
{
// Sync all calendars.
var accounts = await _accountService.GetAccountsAsync().ConfigureAwait(false);
foreach (var account in accounts)
{
var t = new NewCalendarSynchronizationRequested(new CalendarSynchronizationOptions()
{
AccountId = account.Id,
Type = CalendarSynchronizationType.CalendarMetadata
}, SynchronizationSource.Client);
Messenger.Send(t);
}
}
/// <summary>
/// When calendar type switches, we need to navigate to the most ideal date.
/// This method returns that date.
/// </summary>
private DateTime GetDisplayTypeSwitchDate()
{
var settings = PreferencesService.GetCurrentCalendarSettings();
switch (StatePersistenceService.CalendarDisplayType)
{
case CalendarDisplayType.Day:
if (HighlightedDateRange.IsInRange(DateTime.Now)) return DateTime.Now.Date;
return HighlightedDateRange.StartDate;
case CalendarDisplayType.Week:
if (HighlightedDateRange == null || HighlightedDateRange.IsInRange(DateTime.Now))
{
return DateTime.Now.Date.GetWeekStartDateForDate(settings.FirstDayOfWeek);
}
return HighlightedDateRange.StartDate.GetWeekStartDateForDate(settings.FirstDayOfWeek);
case CalendarDisplayType.WorkWeek:
break;
case CalendarDisplayType.Month:
break;
case CalendarDisplayType.Year:
break;
default:
break;
} }
return DateTime.Today.Date; var groupedAccountCalendarViewModel = new GroupedAccountCalendarViewModel(account, calendarViewModels);
}
private DateTime? _navigationDate; await Dispatcher.ExecuteOnUIThread(() =>
private readonly IAccountService _accountService;
private readonly ICalendarService _calendarService;
#region Commands
[RelayCommand]
private void TodayClicked()
{
_navigationDate = DateTime.Now.Date;
ForceNavigateCalendarDate();
}
[RelayCommand]
public void ManageAccounts() => NavigationService.Navigate(WinoPage.AccountManagementPage);
[RelayCommand]
private Task ReconnectServerAsync() => ServerConnectionManager.ConnectAsync();
[RelayCommand]
private void DateClicked(CalendarViewDayClickedEventArgs clickedDateArgs)
{
_navigationDate = clickedDateArgs.ClickedDate;
ForceNavigateCalendarDate();
}
#endregion
public void Receive(VisibleDateRangeChangedMessage message) => HighlightedDateRange = message.DateRange;
/// <summary>
/// Sets the header navigation items based on visible date range and calendar type.
/// </summary>
private void UpdateDateNavigationHeaderItems()
{
DateNavigationHeaderItems.Clear();
// TODO: From settings
var testInfo = new CultureInfo("en-US");
switch (StatePersistenceService.CalendarDisplayType)
{ {
case CalendarDisplayType.Day: AccountCalendarStateService.AddGroupedAccountCalendar(groupedAccountCalendarViewModel);
case CalendarDisplayType.Week:
case CalendarDisplayType.WorkWeek:
case CalendarDisplayType.Month:
DateNavigationHeaderItems.ReplaceRange(testInfo.DateTimeFormat.MonthNames);
break;
case CalendarDisplayType.Year:
break;
default:
break;
}
SetDateNavigationHeaderItems();
}
partial void OnHighlightedDateRangeChanged(DateRange value) => SetDateNavigationHeaderItems();
private void SetDateNavigationHeaderItems()
{
if (HighlightedDateRange == null) return;
if (DateNavigationHeaderItems.Count == 0)
{
UpdateDateNavigationHeaderItems();
}
// TODO: Year view
var monthIndex = HighlightedDateRange.GetMostVisibleMonthIndex();
SelectedDateNavigationHeaderIndex = Math.Max(monthIndex - 1, -1);
}
public async void Receive(CalendarEnableStatusChangedMessage message)
=> await ExecuteUIThread(() => IsCalendarEnabled = message.IsEnabled);
public void Receive(NavigateManageAccountsRequested message) => SelectedMenuItemIndex = 1;
public void Receive(CalendarDisplayTypeChangedMessage message) => OnPropertyChanged(nameof(IsVerticalCalendar));
public async void Receive(DetailsPageStateChangedMessage message)
{
await ExecuteUIThread(() =>
{
IsEventDetailsPageActive = message.IsActivated;
// TODO: This is for Wino Mail. Generalize this later on.
StatePersistenceService.IsReaderNarrowed = message.IsActivated;
StatePersistenceService.IsReadingMail = message.IsActivated;
}); });
} }
} }
private void ForceNavigateCalendarDate()
{
if (SelectedMenuItemIndex == -1)
{
var args = new CalendarPageNavigationArgs()
{
NavigationDate = _navigationDate ?? DateTime.Now.Date
};
// Already on calendar. Just navigate.
NavigationService.Navigate(WinoPage.CalendarPage, args);
_navigationDate = null;
}
else
{
SelectedMenuItemIndex = -1;
}
}
partial void OnSelectedMenuItemIndexChanged(int oldValue, int newValue)
{
switch (newValue)
{
case -1:
ForceNavigateCalendarDate();
break;
case 0:
NavigationService.Navigate(WinoPage.ManageAccountsPage);
break;
case 1:
NavigationService.Navigate(WinoPage.SettingsPage);
break;
default:
break;
}
}
[RelayCommand]
private async Task Sync()
{
// Sync all calendars.
var accounts = await _accountService.GetAccountsAsync().ConfigureAwait(false);
foreach (var account in accounts)
{
var t = new NewCalendarSynchronizationRequested(new CalendarSynchronizationOptions()
{
AccountId = account.Id,
Type = CalendarSynchronizationType.CalendarMetadata
}, SynchronizationSource.Client);
Messenger.Send(t);
}
}
/// <summary>
/// When calendar type switches, we need to navigate to the most ideal date.
/// This method returns that date.
/// </summary>
private DateTime GetDisplayTypeSwitchDate()
{
var settings = PreferencesService.GetCurrentCalendarSettings();
switch (StatePersistenceService.CalendarDisplayType)
{
case CalendarDisplayType.Day:
if (HighlightedDateRange.IsInRange(DateTime.Now)) return DateTime.Now.Date;
return HighlightedDateRange.StartDate;
case CalendarDisplayType.Week:
if (HighlightedDateRange == null || HighlightedDateRange.IsInRange(DateTime.Now))
{
return DateTime.Now.Date.GetWeekStartDateForDate(settings.FirstDayOfWeek);
}
return HighlightedDateRange.StartDate.GetWeekStartDateForDate(settings.FirstDayOfWeek);
case CalendarDisplayType.WorkWeek:
break;
case CalendarDisplayType.Month:
break;
case CalendarDisplayType.Year:
break;
default:
break;
}
return DateTime.Today.Date;
}
private DateTime? _navigationDate;
private readonly IAccountService _accountService;
private readonly ICalendarService _calendarService;
#region Commands
[RelayCommand]
private void TodayClicked()
{
_navigationDate = DateTime.Now.Date;
ForceNavigateCalendarDate();
}
[RelayCommand]
public void ManageAccounts() => NavigationService.Navigate(WinoPage.AccountManagementPage);
[RelayCommand]
private Task ReconnectServerAsync() => ServerConnectionManager.ConnectAsync();
[RelayCommand]
private void DateClicked(CalendarViewDayClickedEventArgs clickedDateArgs)
{
_navigationDate = clickedDateArgs.ClickedDate;
ForceNavigateCalendarDate();
}
#endregion
public void Receive(VisibleDateRangeChangedMessage message) => HighlightedDateRange = message.DateRange;
/// <summary>
/// Sets the header navigation items based on visible date range and calendar type.
/// </summary>
private void UpdateDateNavigationHeaderItems()
{
DateNavigationHeaderItems.Clear();
// TODO: From settings
var testInfo = new CultureInfo("en-US");
switch (StatePersistenceService.CalendarDisplayType)
{
case CalendarDisplayType.Day:
case CalendarDisplayType.Week:
case CalendarDisplayType.WorkWeek:
case CalendarDisplayType.Month:
DateNavigationHeaderItems.ReplaceRange(testInfo.DateTimeFormat.MonthNames);
break;
case CalendarDisplayType.Year:
break;
default:
break;
}
SetDateNavigationHeaderItems();
}
partial void OnHighlightedDateRangeChanged(DateRange value) => SetDateNavigationHeaderItems();
private void SetDateNavigationHeaderItems()
{
if (HighlightedDateRange == null) return;
if (DateNavigationHeaderItems.Count == 0)
{
UpdateDateNavigationHeaderItems();
}
// TODO: Year view
var monthIndex = HighlightedDateRange.GetMostVisibleMonthIndex();
SelectedDateNavigationHeaderIndex = Math.Max(monthIndex - 1, -1);
}
public async void Receive(CalendarEnableStatusChangedMessage message)
=> await ExecuteUIThread(() => IsCalendarEnabled = message.IsEnabled);
public void Receive(NavigateManageAccountsRequested message) => SelectedMenuItemIndex = 1;
public void Receive(CalendarDisplayTypeChangedMessage message) => OnPropertyChanged(nameof(IsVerticalCalendar));
public async void Receive(DetailsPageStateChangedMessage message)
{
await ExecuteUIThread(() =>
{
IsEventDetailsPageActive = message.IsActivated;
// TODO: This is for Wino Mail. Generalize this later on.
StatePersistenceService.IsReaderNarrowed = message.IsActivated;
StatePersistenceService.IsReadingMail = message.IsActivated;
});
}
} }

File diff suppressed because it is too large Load Diff

View File

@@ -8,120 +8,119 @@ using Wino.Core.Domain.Translations;
using Wino.Core.ViewModels; using Wino.Core.ViewModels;
using Wino.Messaging.Client.Calendar; using Wino.Messaging.Client.Calendar;
namespace Wino.Calendar.ViewModels namespace Wino.Calendar.ViewModels;
public partial class CalendarSettingsPageViewModel : CalendarBaseViewModel
{ {
public partial class CalendarSettingsPageViewModel : CalendarBaseViewModel [ObservableProperty]
private double _cellHourHeight;
[ObservableProperty]
private int _selectedFirstDayOfWeekIndex;
[ObservableProperty]
private bool _is24HourHeaders;
[ObservableProperty]
private TimeSpan _workingHourStart;
[ObservableProperty]
private TimeSpan _workingHourEnd;
[ObservableProperty]
private List<string> _dayNames = [];
[ObservableProperty]
private int _workingDayStartIndex;
[ObservableProperty]
private int _workingDayEndIndex;
public IPreferencesService PreferencesService { get; }
private readonly bool _isLoaded = false;
public CalendarSettingsPageViewModel(IPreferencesService preferencesService)
{ {
[ObservableProperty] PreferencesService = preferencesService;
private double _cellHourHeight;
[ObservableProperty] var currentLanguageLanguageCode = WinoTranslationDictionary.GetLanguageFileNameRelativePath(preferencesService.CurrentLanguage);
private int _selectedFirstDayOfWeekIndex;
[ObservableProperty] var cultureInfo = new CultureInfo(currentLanguageLanguageCode);
private bool _is24HourHeaders;
[ObservableProperty] // Populate the day names list
private TimeSpan _workingHourStart; for (var i = 0; i < 7; i++)
[ObservableProperty]
private TimeSpan _workingHourEnd;
[ObservableProperty]
private List<string> _dayNames = [];
[ObservableProperty]
private int _workingDayStartIndex;
[ObservableProperty]
private int _workingDayEndIndex;
public IPreferencesService PreferencesService { get; }
private readonly bool _isLoaded = false;
public CalendarSettingsPageViewModel(IPreferencesService preferencesService)
{ {
PreferencesService = preferencesService; _dayNames.Add(cultureInfo.DateTimeFormat.DayNames[i]);
var currentLanguageLanguageCode = WinoTranslationDictionary.GetLanguageFileNameRelativePath(preferencesService.CurrentLanguage);
var cultureInfo = new CultureInfo(currentLanguageLanguageCode);
// Populate the day names list
for (var i = 0; i < 7; i++)
{
_dayNames.Add(cultureInfo.DateTimeFormat.DayNames[i]);
}
var cultureFirstDayName = cultureInfo.DateTimeFormat.GetDayName(preferencesService.FirstDayOfWeek);
_selectedFirstDayOfWeekIndex = _dayNames.IndexOf(cultureFirstDayName);
_is24HourHeaders = preferencesService.Prefer24HourTimeFormat;
_workingHourStart = preferencesService.WorkingHourStart;
_workingHourEnd = preferencesService.WorkingHourEnd;
_cellHourHeight = preferencesService.HourHeight;
_workingDayStartIndex = _dayNames.IndexOf(cultureInfo.DateTimeFormat.GetDayName(preferencesService.WorkingDayStart));
_workingDayEndIndex = _dayNames.IndexOf(cultureInfo.DateTimeFormat.GetDayName(preferencesService.WorkingDayEnd));
_isLoaded = true;
} }
partial void OnCellHourHeightChanged(double oldValue, double newValue) => SaveSettings(); var cultureFirstDayName = cultureInfo.DateTimeFormat.GetDayName(preferencesService.FirstDayOfWeek);
partial void OnIs24HourHeadersChanged(bool value) => SaveSettings();
partial void OnSelectedFirstDayOfWeekIndexChanged(int value) => SaveSettings();
partial void OnWorkingHourStartChanged(TimeSpan value) => SaveSettings();
partial void OnWorkingHourEndChanged(TimeSpan value) => SaveSettings();
partial void OnWorkingDayStartIndexChanged(int value) => SaveSettings();
partial void OnWorkingDayEndIndexChanged(int value) => SaveSettings();
public void SaveSettings() _selectedFirstDayOfWeekIndex = _dayNames.IndexOf(cultureFirstDayName);
_is24HourHeaders = preferencesService.Prefer24HourTimeFormat;
_workingHourStart = preferencesService.WorkingHourStart;
_workingHourEnd = preferencesService.WorkingHourEnd;
_cellHourHeight = preferencesService.HourHeight;
_workingDayStartIndex = _dayNames.IndexOf(cultureInfo.DateTimeFormat.GetDayName(preferencesService.WorkingDayStart));
_workingDayEndIndex = _dayNames.IndexOf(cultureInfo.DateTimeFormat.GetDayName(preferencesService.WorkingDayEnd));
_isLoaded = true;
}
partial void OnCellHourHeightChanged(double oldValue, double newValue) => SaveSettings();
partial void OnIs24HourHeadersChanged(bool value) => SaveSettings();
partial void OnSelectedFirstDayOfWeekIndexChanged(int value) => SaveSettings();
partial void OnWorkingHourStartChanged(TimeSpan value) => SaveSettings();
partial void OnWorkingHourEndChanged(TimeSpan value) => SaveSettings();
partial void OnWorkingDayStartIndexChanged(int value) => SaveSettings();
partial void OnWorkingDayEndIndexChanged(int value) => SaveSettings();
public void SaveSettings()
{
if (!_isLoaded) return;
PreferencesService.FirstDayOfWeek = SelectedFirstDayOfWeekIndex switch
{ {
if (!_isLoaded) return; 0 => DayOfWeek.Sunday,
1 => DayOfWeek.Monday,
2 => DayOfWeek.Tuesday,
3 => DayOfWeek.Wednesday,
4 => DayOfWeek.Thursday,
5 => DayOfWeek.Friday,
6 => DayOfWeek.Saturday,
_ => throw new ArgumentOutOfRangeException()
};
PreferencesService.FirstDayOfWeek = SelectedFirstDayOfWeekIndex switch PreferencesService.WorkingDayStart = WorkingDayStartIndex switch
{ {
0 => DayOfWeek.Sunday, 0 => DayOfWeek.Sunday,
1 => DayOfWeek.Monday, 1 => DayOfWeek.Monday,
2 => DayOfWeek.Tuesday, 2 => DayOfWeek.Tuesday,
3 => DayOfWeek.Wednesday, 3 => DayOfWeek.Wednesday,
4 => DayOfWeek.Thursday, 4 => DayOfWeek.Thursday,
5 => DayOfWeek.Friday, 5 => DayOfWeek.Friday,
6 => DayOfWeek.Saturday, 6 => DayOfWeek.Saturday,
_ => throw new ArgumentOutOfRangeException() _ => throw new ArgumentOutOfRangeException()
}; };
PreferencesService.WorkingDayStart = WorkingDayStartIndex switch PreferencesService.WorkingDayEnd = WorkingDayEndIndex switch
{ {
0 => DayOfWeek.Sunday, 0 => DayOfWeek.Sunday,
1 => DayOfWeek.Monday, 1 => DayOfWeek.Monday,
2 => DayOfWeek.Tuesday, 2 => DayOfWeek.Tuesday,
3 => DayOfWeek.Wednesday, 3 => DayOfWeek.Wednesday,
4 => DayOfWeek.Thursday, 4 => DayOfWeek.Thursday,
5 => DayOfWeek.Friday, 5 => DayOfWeek.Friday,
6 => DayOfWeek.Saturday, 6 => DayOfWeek.Saturday,
_ => throw new ArgumentOutOfRangeException() _ => throw new ArgumentOutOfRangeException()
}; };
PreferencesService.WorkingDayEnd = WorkingDayEndIndex switch PreferencesService.Prefer24HourTimeFormat = Is24HourHeaders;
{ PreferencesService.WorkingHourStart = WorkingHourStart;
0 => DayOfWeek.Sunday, PreferencesService.WorkingHourEnd = WorkingHourEnd;
1 => DayOfWeek.Monday, PreferencesService.HourHeight = CellHourHeight;
2 => DayOfWeek.Tuesday,
3 => DayOfWeek.Wednesday,
4 => DayOfWeek.Thursday,
5 => DayOfWeek.Friday,
6 => DayOfWeek.Saturday,
_ => throw new ArgumentOutOfRangeException()
};
PreferencesService.Prefer24HourTimeFormat = Is24HourHeaders; Messenger.Send(new CalendarSettingsUpdatedMessage());
PreferencesService.WorkingHourStart = WorkingHourStart;
PreferencesService.WorkingHourEnd = WorkingHourEnd;
PreferencesService.HourHeight = CellHourHeight;
Messenger.Send(new CalendarSettingsUpdatedMessage());
}
} }
} }

View File

@@ -1,13 +1,12 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Wino.Core; using Wino.Core;
namespace Wino.Calendar.ViewModels namespace Wino.Calendar.ViewModels;
public static class CalendarViewModelContainerSetup
{ {
public static class CalendarViewModelContainerSetup public static void RegisterCalendarViewModelServices(this IServiceCollection services)
{ {
public static void RegisterCalendarViewModelServices(this IServiceCollection services) services.RegisterCoreServices();
{
services.RegisterCoreServices();
}
} }
} }

View File

@@ -4,67 +4,66 @@ using Wino.Core.Domain.Entities.Calendar;
using Wino.Core.Domain.Entities.Shared; using Wino.Core.Domain.Entities.Shared;
using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Interfaces;
namespace Wino.Calendar.ViewModels.Data namespace Wino.Calendar.ViewModels.Data;
public partial class AccountCalendarViewModel : ObservableObject, IAccountCalendar
{ {
public partial class AccountCalendarViewModel : ObservableObject, IAccountCalendar public MailAccount Account { get; }
public AccountCalendar AccountCalendar { get; }
public AccountCalendarViewModel(MailAccount account, AccountCalendar accountCalendar)
{ {
public MailAccount Account { get; } Account = account;
public AccountCalendar AccountCalendar { get; } AccountCalendar = accountCalendar;
public AccountCalendarViewModel(MailAccount account, AccountCalendar accountCalendar) IsChecked = accountCalendar.IsExtended;
{
Account = account;
AccountCalendar = accountCalendar;
IsChecked = accountCalendar.IsExtended;
}
[ObservableProperty]
private bool _isChecked;
partial void OnIsCheckedChanged(bool value) => IsExtended = value;
public string Name
{
get => AccountCalendar.Name;
set => SetProperty(AccountCalendar.Name, value, AccountCalendar, (u, n) => u.Name = n);
}
public string TextColorHex
{
get => AccountCalendar.TextColorHex;
set => SetProperty(AccountCalendar.TextColorHex, value, AccountCalendar, (u, t) => u.TextColorHex = t);
}
public string BackgroundColorHex
{
get => AccountCalendar.BackgroundColorHex;
set => SetProperty(AccountCalendar.BackgroundColorHex, value, AccountCalendar, (u, b) => u.BackgroundColorHex = b);
}
public bool IsExtended
{
get => AccountCalendar.IsExtended;
set => SetProperty(AccountCalendar.IsExtended, value, AccountCalendar, (u, i) => u.IsExtended = i);
}
public bool IsPrimary
{
get => AccountCalendar.IsPrimary;
set => SetProperty(AccountCalendar.IsPrimary, value, AccountCalendar, (u, i) => u.IsPrimary = i);
}
public Guid AccountId
{
get => AccountCalendar.AccountId;
set => SetProperty(AccountCalendar.AccountId, value, AccountCalendar, (u, a) => u.AccountId = a);
}
public string RemoteCalendarId
{
get => AccountCalendar.RemoteCalendarId;
set => SetProperty(AccountCalendar.RemoteCalendarId, value, AccountCalendar, (u, r) => u.RemoteCalendarId = r);
}
public Guid Id { get => ((IAccountCalendar)AccountCalendar).Id; set => ((IAccountCalendar)AccountCalendar).Id = value; }
} }
[ObservableProperty]
private bool _isChecked;
partial void OnIsCheckedChanged(bool value) => IsExtended = value;
public string Name
{
get => AccountCalendar.Name;
set => SetProperty(AccountCalendar.Name, value, AccountCalendar, (u, n) => u.Name = n);
}
public string TextColorHex
{
get => AccountCalendar.TextColorHex;
set => SetProperty(AccountCalendar.TextColorHex, value, AccountCalendar, (u, t) => u.TextColorHex = t);
}
public string BackgroundColorHex
{
get => AccountCalendar.BackgroundColorHex;
set => SetProperty(AccountCalendar.BackgroundColorHex, value, AccountCalendar, (u, b) => u.BackgroundColorHex = b);
}
public bool IsExtended
{
get => AccountCalendar.IsExtended;
set => SetProperty(AccountCalendar.IsExtended, value, AccountCalendar, (u, i) => u.IsExtended = i);
}
public bool IsPrimary
{
get => AccountCalendar.IsPrimary;
set => SetProperty(AccountCalendar.IsPrimary, value, AccountCalendar, (u, i) => u.IsPrimary = i);
}
public Guid AccountId
{
get => AccountCalendar.AccountId;
set => SetProperty(AccountCalendar.AccountId, value, AccountCalendar, (u, a) => u.AccountId = a);
}
public string RemoteCalendarId
{
get => AccountCalendar.RemoteCalendarId;
set => SetProperty(AccountCalendar.RemoteCalendarId, value, AccountCalendar, (u, r) => u.RemoteCalendarId = r);
}
public Guid Id { get => ((IAccountCalendar)AccountCalendar).Id; set => ((IAccountCalendar)AccountCalendar).Id = value; }
} }

View File

@@ -5,42 +5,41 @@ using Itenso.TimePeriod;
using Wino.Core.Domain.Entities.Calendar; using Wino.Core.Domain.Entities.Calendar;
using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Interfaces;
namespace Wino.Calendar.ViewModels.Data namespace Wino.Calendar.ViewModels.Data;
public partial class CalendarItemViewModel : ObservableObject, ICalendarItem, ICalendarItemViewModel
{ {
public partial class CalendarItemViewModel : ObservableObject, ICalendarItem, ICalendarItemViewModel public CalendarItem CalendarItem { get; }
public string Title => CalendarItem.Title;
public Guid Id => CalendarItem.Id;
public IAccountCalendar AssignedCalendar => CalendarItem.AssignedCalendar;
public DateTime StartDate { get => CalendarItem.StartDate; set => CalendarItem.StartDate = value; }
public DateTime EndDate => CalendarItem.EndDate;
public double DurationInSeconds { get => CalendarItem.DurationInSeconds; set => CalendarItem.DurationInSeconds = value; }
public ITimePeriod Period => CalendarItem.Period;
public bool IsAllDayEvent => CalendarItem.IsAllDayEvent;
public bool IsMultiDayEvent => CalendarItem.IsMultiDayEvent;
public bool IsRecurringEvent => CalendarItem.IsRecurringEvent;
public bool IsRecurringChild => CalendarItem.IsRecurringChild;
public bool IsRecurringParent => CalendarItem.IsRecurringParent;
[ObservableProperty]
private bool _isSelected;
public ObservableCollection<CalendarEventAttendee> Attendees { get; } = new ObservableCollection<CalendarEventAttendee>();
public CalendarItemViewModel(CalendarItem calendarItem)
{ {
public CalendarItem CalendarItem { get; } CalendarItem = calendarItem;
public string Title => CalendarItem.Title;
public Guid Id => CalendarItem.Id;
public IAccountCalendar AssignedCalendar => CalendarItem.AssignedCalendar;
public DateTime StartDate { get => CalendarItem.StartDate; set => CalendarItem.StartDate = value; }
public DateTime EndDate => CalendarItem.EndDate;
public double DurationInSeconds { get => CalendarItem.DurationInSeconds; set => CalendarItem.DurationInSeconds = value; }
public ITimePeriod Period => CalendarItem.Period;
public bool IsAllDayEvent => CalendarItem.IsAllDayEvent;
public bool IsMultiDayEvent => CalendarItem.IsMultiDayEvent;
public bool IsRecurringEvent => CalendarItem.IsRecurringEvent;
public bool IsRecurringChild => CalendarItem.IsRecurringChild;
public bool IsRecurringParent => CalendarItem.IsRecurringParent;
[ObservableProperty]
private bool _isSelected;
public ObservableCollection<CalendarEventAttendee> Attendees { get; } = new ObservableCollection<CalendarEventAttendee>();
public CalendarItemViewModel(CalendarItem calendarItem)
{
CalendarItem = calendarItem;
}
public override string ToString() => CalendarItem.Title;
} }
public override string ToString() => CalendarItem.Title;
} }

View File

@@ -6,141 +6,140 @@ using System.Linq;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using Wino.Core.Domain.Entities.Shared; using Wino.Core.Domain.Entities.Shared;
namespace Wino.Calendar.ViewModels.Data namespace Wino.Calendar.ViewModels.Data;
public partial class GroupedAccountCalendarViewModel : ObservableObject
{ {
public partial class GroupedAccountCalendarViewModel : ObservableObject public event EventHandler CollectiveSelectionStateChanged;
public event EventHandler<AccountCalendarViewModel> CalendarSelectionStateChanged;
public MailAccount Account { get; }
public ObservableCollection<AccountCalendarViewModel> AccountCalendars { get; }
public GroupedAccountCalendarViewModel(MailAccount account, IEnumerable<AccountCalendarViewModel> calendarViewModels)
{ {
public event EventHandler CollectiveSelectionStateChanged; Account = account;
public event EventHandler<AccountCalendarViewModel> CalendarSelectionStateChanged; AccountCalendars = new ObservableCollection<AccountCalendarViewModel>(calendarViewModels);
public MailAccount Account { get; } ManageIsCheckedState();
public ObservableCollection<AccountCalendarViewModel> AccountCalendars { get; }
public GroupedAccountCalendarViewModel(MailAccount account, IEnumerable<AccountCalendarViewModel> calendarViewModels) foreach (var calendarViewModel in calendarViewModels)
{ {
Account = account; calendarViewModel.PropertyChanged += CalendarPropertyChanged;
AccountCalendars = new ObservableCollection<AccountCalendarViewModel>(calendarViewModels);
ManageIsCheckedState();
foreach (var calendarViewModel in calendarViewModels)
{
calendarViewModel.PropertyChanged += CalendarPropertyChanged;
}
AccountCalendars.CollectionChanged += CalendarListUpdated;
} }
private void CalendarListUpdated(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) AccountCalendars.CollectionChanged += CalendarListUpdated;
}
private void CalendarListUpdated(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{ {
if (e.Action == NotifyCollectionChangedAction.Add) foreach (AccountCalendarViewModel calendar in e.NewItems)
{ {
foreach (AccountCalendarViewModel calendar in e.NewItems) calendar.PropertyChanged += CalendarPropertyChanged;
{
calendar.PropertyChanged += CalendarPropertyChanged;
}
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
foreach (AccountCalendarViewModel calendar in e.OldItems)
{
calendar.PropertyChanged -= CalendarPropertyChanged;
}
}
else if (e.Action == NotifyCollectionChangedAction.Reset)
{
foreach (AccountCalendarViewModel calendar in e.OldItems)
{
calendar.PropertyChanged -= CalendarPropertyChanged;
}
} }
} }
else if (e.Action == NotifyCollectionChangedAction.Remove)
private void CalendarPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{ {
if (sender is AccountCalendarViewModel viewModel) foreach (AccountCalendarViewModel calendar in e.OldItems)
{ {
if (e.PropertyName == nameof(AccountCalendarViewModel.IsChecked)) calendar.PropertyChanged -= CalendarPropertyChanged;
{
ManageIsCheckedState();
UpdateCalendarCheckedState(viewModel, viewModel.IsChecked, true);
}
} }
} }
else if (e.Action == NotifyCollectionChangedAction.Reset)
[ObservableProperty]
private bool _isExpanded = true;
[ObservableProperty]
private bool? isCheckedState = true;
private bool _isExternalPropChangeBlocked = false;
private void ManageIsCheckedState()
{ {
if (_isExternalPropChangeBlocked) return; foreach (AccountCalendarViewModel calendar in e.OldItems)
_isExternalPropChangeBlocked = true;
if (AccountCalendars.All(c => c.IsChecked))
{ {
IsCheckedState = true; calendar.PropertyChanged -= CalendarPropertyChanged;
} }
else if (AccountCalendars.All(c => !c.IsChecked))
{
IsCheckedState = false;
}
else
{
IsCheckedState = null;
}
_isExternalPropChangeBlocked = false;
}
partial void OnIsCheckedStateChanged(bool? newValue)
{
if (_isExternalPropChangeBlocked) return;
// Update is triggered by user on the three-state checkbox.
// We should not report all changes one by one.
_isExternalPropChangeBlocked = true;
if (newValue == null)
{
// Only primary calendars must be checked.
foreach (var calendar in AccountCalendars)
{
UpdateCalendarCheckedState(calendar, calendar.IsPrimary);
}
}
else
{
foreach (var calendar in AccountCalendars)
{
UpdateCalendarCheckedState(calendar, newValue.GetValueOrDefault());
}
}
_isExternalPropChangeBlocked = false;
CollectiveSelectionStateChanged?.Invoke(this, EventArgs.Empty);
}
private void UpdateCalendarCheckedState(AccountCalendarViewModel accountCalendarViewModel, bool newValue, bool ignoreValueCheck = false)
{
var currentValue = accountCalendarViewModel.IsChecked;
if (currentValue == newValue && !ignoreValueCheck) return;
accountCalendarViewModel.IsChecked = newValue;
// No need to report.
if (_isExternalPropChangeBlocked == true) return;
CalendarSelectionStateChanged?.Invoke(this, accountCalendarViewModel);
} }
} }
private void CalendarPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (sender is AccountCalendarViewModel viewModel)
{
if (e.PropertyName == nameof(AccountCalendarViewModel.IsChecked))
{
ManageIsCheckedState();
UpdateCalendarCheckedState(viewModel, viewModel.IsChecked, true);
}
}
}
[ObservableProperty]
private bool _isExpanded = true;
[ObservableProperty]
private bool? isCheckedState = true;
private bool _isExternalPropChangeBlocked = false;
private void ManageIsCheckedState()
{
if (_isExternalPropChangeBlocked) return;
_isExternalPropChangeBlocked = true;
if (AccountCalendars.All(c => c.IsChecked))
{
IsCheckedState = true;
}
else if (AccountCalendars.All(c => !c.IsChecked))
{
IsCheckedState = false;
}
else
{
IsCheckedState = null;
}
_isExternalPropChangeBlocked = false;
}
partial void OnIsCheckedStateChanged(bool? newValue)
{
if (_isExternalPropChangeBlocked) return;
// Update is triggered by user on the three-state checkbox.
// We should not report all changes one by one.
_isExternalPropChangeBlocked = true;
if (newValue == null)
{
// Only primary calendars must be checked.
foreach (var calendar in AccountCalendars)
{
UpdateCalendarCheckedState(calendar, calendar.IsPrimary);
}
}
else
{
foreach (var calendar in AccountCalendars)
{
UpdateCalendarCheckedState(calendar, newValue.GetValueOrDefault());
}
}
_isExternalPropChangeBlocked = false;
CollectiveSelectionStateChanged?.Invoke(this, EventArgs.Empty);
}
private void UpdateCalendarCheckedState(AccountCalendarViewModel accountCalendarViewModel, bool newValue, bool ignoreValueCheck = false)
{
var currentValue = accountCalendarViewModel.IsChecked;
if (currentValue == newValue && !ignoreValueCheck) return;
accountCalendarViewModel.IsChecked = newValue;
// No need to report.
if (_isExternalPropChangeBlocked == true) return;
CalendarSelectionStateChanged?.Invoke(this, accountCalendarViewModel);
}
} }

View File

@@ -12,105 +12,104 @@ using Wino.Core.Domain.Models.Navigation;
using Wino.Core.ViewModels; using Wino.Core.ViewModels;
using Wino.Messaging.Client.Calendar; using Wino.Messaging.Client.Calendar;
namespace Wino.Calendar.ViewModels namespace Wino.Calendar.ViewModels;
public partial class EventDetailsPageViewModel : CalendarBaseViewModel
{ {
public partial class EventDetailsPageViewModel : CalendarBaseViewModel private readonly ICalendarService _calendarService;
private readonly INativeAppService _nativeAppService;
private readonly IPreferencesService _preferencesService;
public CalendarSettings CurrentSettings { get; }
#region Details
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(CanViewSeries))]
private CalendarItemViewModel _currentEvent;
[ObservableProperty]
private CalendarItemViewModel _seriesParent;
public bool CanViewSeries => CurrentEvent?.IsRecurringChild ?? false;
#endregion
public EventDetailsPageViewModel(ICalendarService calendarService, INativeAppService nativeAppService, IPreferencesService preferencesService)
{ {
private readonly ICalendarService _calendarService; _calendarService = calendarService;
private readonly INativeAppService _nativeAppService; _nativeAppService = nativeAppService;
private readonly IPreferencesService _preferencesService; _preferencesService = preferencesService;
public CalendarSettings CurrentSettings { get; } CurrentSettings = _preferencesService.GetCurrentCalendarSettings();
}
#region Details public override async void OnNavigatedTo(NavigationMode mode, object parameters)
{
base.OnNavigatedTo(mode, parameters);
[ObservableProperty] Messenger.Send(new DetailsPageStateChangedMessage(true));
[NotifyPropertyChangedFor(nameof(CanViewSeries))]
private CalendarItemViewModel _currentEvent;
[ObservableProperty] if (parameters == null || parameters is not CalendarItemTarget args)
private CalendarItemViewModel _seriesParent; return;
public bool CanViewSeries => CurrentEvent?.IsRecurringChild ?? false; await LoadCalendarItemTargetAsync(args);
}
#endregion private async Task LoadCalendarItemTargetAsync(CalendarItemTarget target)
{
public EventDetailsPageViewModel(ICalendarService calendarService, INativeAppService nativeAppService, IPreferencesService preferencesService) try
{ {
_calendarService = calendarService; var currentEventItem = await _calendarService.GetCalendarItemTargetAsync(target);
_nativeAppService = nativeAppService;
_preferencesService = preferencesService;
CurrentSettings = _preferencesService.GetCurrentCalendarSettings(); if (currentEventItem == null)
}
public override async void OnNavigatedTo(NavigationMode mode, object parameters)
{
base.OnNavigatedTo(mode, parameters);
Messenger.Send(new DetailsPageStateChangedMessage(true));
if (parameters == null || parameters is not CalendarItemTarget args)
return; return;
await LoadCalendarItemTargetAsync(args); CurrentEvent = new CalendarItemViewModel(currentEventItem);
}
private async Task LoadCalendarItemTargetAsync(CalendarItemTarget target) var attendees = await _calendarService.GetAttendeesAsync(currentEventItem.EventTrackingId);
{
try foreach (var item in attendees)
{ {
var currentEventItem = await _calendarService.GetCalendarItemTargetAsync(target); CurrentEvent.Attendees.Add(item);
if (currentEventItem == null)
return;
CurrentEvent = new CalendarItemViewModel(currentEventItem);
var attendees = await _calendarService.GetAttendeesAsync(currentEventItem.EventTrackingId);
foreach (var item in attendees)
{
CurrentEvent.Attendees.Add(item);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
} }
} }
catch (Exception ex)
public override void OnNavigatedFrom(NavigationMode mode, object parameters)
{ {
base.OnNavigatedFrom(mode, parameters); Debug.WriteLine(ex.Message);
Messenger.Send(new DetailsPageStateChangedMessage(false));
}
[RelayCommand]
private async Task SaveAsync()
{
}
[RelayCommand]
private async Task DeleteAsync()
{
}
[RelayCommand]
private Task JoinOnline()
{
if (CurrentEvent == null || string.IsNullOrEmpty(CurrentEvent.CalendarItem.HtmlLink)) return Task.CompletedTask;
return _nativeAppService.LaunchUriAsync(new Uri(CurrentEvent.CalendarItem.HtmlLink));
}
[RelayCommand]
private async Task Respond(CalendarItemStatus status)
{
if (CurrentEvent == null) return;
} }
} }
public override void OnNavigatedFrom(NavigationMode mode, object parameters)
{
base.OnNavigatedFrom(mode, parameters);
Messenger.Send(new DetailsPageStateChangedMessage(false));
}
[RelayCommand]
private async Task SaveAsync()
{
}
[RelayCommand]
private async Task DeleteAsync()
{
}
[RelayCommand]
private Task JoinOnline()
{
if (CurrentEvent == null || string.IsNullOrEmpty(CurrentEvent.CalendarItem.HtmlLink)) return Task.CompletedTask;
return _nativeAppService.LaunchUriAsync(new Uri(CurrentEvent.CalendarItem.HtmlLink));
}
[RelayCommand]
private async Task Respond(CalendarItemStatus status)
{
if (CurrentEvent == null) return;
}
} }

View File

@@ -6,26 +6,25 @@ using System.Linq;
using Wino.Calendar.ViewModels.Data; using Wino.Calendar.ViewModels.Data;
using Wino.Core.Domain.Entities.Shared; using Wino.Core.Domain.Entities.Shared;
namespace Wino.Calendar.ViewModels.Interfaces namespace Wino.Calendar.ViewModels.Interfaces;
public interface IAccountCalendarStateService : INotifyPropertyChanged
{ {
public interface IAccountCalendarStateService : INotifyPropertyChanged ReadOnlyObservableCollection<GroupedAccountCalendarViewModel> GroupedAccountCalendars { get; }
{
ReadOnlyObservableCollection<GroupedAccountCalendarViewModel> GroupedAccountCalendars { get; }
event EventHandler<GroupedAccountCalendarViewModel> CollectiveAccountGroupSelectionStateChanged; event EventHandler<GroupedAccountCalendarViewModel> CollectiveAccountGroupSelectionStateChanged;
event EventHandler<AccountCalendarViewModel> AccountCalendarSelectionStateChanged; event EventHandler<AccountCalendarViewModel> AccountCalendarSelectionStateChanged;
public void AddGroupedAccountCalendar(GroupedAccountCalendarViewModel groupedAccountCalendar); public void AddGroupedAccountCalendar(GroupedAccountCalendarViewModel groupedAccountCalendar);
public void RemoveGroupedAccountCalendar(GroupedAccountCalendarViewModel groupedAccountCalendar); public void RemoveGroupedAccountCalendar(GroupedAccountCalendarViewModel groupedAccountCalendar);
public void ClearGroupedAccountCalendar(); public void ClearGroupedAccountCalendar();
public void AddAccountCalendar(AccountCalendarViewModel accountCalendar); public void AddAccountCalendar(AccountCalendarViewModel accountCalendar);
public void RemoveAccountCalendar(AccountCalendarViewModel accountCalendar); public void RemoveAccountCalendar(AccountCalendarViewModel accountCalendar);
/// <summary> /// <summary>
/// Enumeration of currently selected calendars. /// Enumeration of currently selected calendars.
/// </summary> /// </summary>
IEnumerable<AccountCalendarViewModel> ActiveCalendars { get; } IEnumerable<AccountCalendarViewModel> ActiveCalendars { get; }
IEnumerable<IGrouping<MailAccount, AccountCalendarViewModel>> GroupedAccountCalendarsEnumerable { get; } IEnumerable<IGrouping<MailAccount, AccountCalendarViewModel>> GroupedAccountCalendarsEnumerable { get; }
}
} }

View File

@@ -1,14 +1,13 @@
using Wino.Calendar.ViewModels.Data; using Wino.Calendar.ViewModels.Data;
namespace Wino.Calendar.ViewModels.Messages namespace Wino.Calendar.ViewModels.Messages;
{
public class CalendarItemDoubleTappedMessage
{
public CalendarItemDoubleTappedMessage(CalendarItemViewModel calendarItemViewModel)
{
CalendarItemViewModel = calendarItemViewModel;
}
public CalendarItemViewModel CalendarItemViewModel { get; } public class CalendarItemDoubleTappedMessage
{
public CalendarItemDoubleTappedMessage(CalendarItemViewModel calendarItemViewModel)
{
CalendarItemViewModel = calendarItemViewModel;
} }
public CalendarItemViewModel CalendarItemViewModel { get; }
} }

View File

@@ -1,14 +1,13 @@
using Wino.Calendar.ViewModels.Data; using Wino.Calendar.ViewModels.Data;
namespace Wino.Calendar.ViewModels.Messages namespace Wino.Calendar.ViewModels.Messages;
{
public class CalendarItemRightTappedMessage
{
public CalendarItemRightTappedMessage(CalendarItemViewModel calendarItemViewModel)
{
CalendarItemViewModel = calendarItemViewModel;
}
public CalendarItemViewModel CalendarItemViewModel { get; } public class CalendarItemRightTappedMessage
{
public CalendarItemRightTappedMessage(CalendarItemViewModel calendarItemViewModel)
{
CalendarItemViewModel = calendarItemViewModel;
} }
public CalendarItemViewModel CalendarItemViewModel { get; }
} }

View File

@@ -1,17 +1,16 @@
using Wino.Calendar.ViewModels.Data; using Wino.Calendar.ViewModels.Data;
using Wino.Core.Domain.Models.Calendar; using Wino.Core.Domain.Models.Calendar;
namespace Wino.Calendar.ViewModels.Messages namespace Wino.Calendar.ViewModels.Messages;
{
public class CalendarItemTappedMessage
{
public CalendarItemTappedMessage(CalendarItemViewModel calendarItemViewModel, CalendarDayModel clickedPeriod)
{
CalendarItemViewModel = calendarItemViewModel;
ClickedPeriod = clickedPeriod;
}
public CalendarItemViewModel CalendarItemViewModel { get; } public class CalendarItemTappedMessage
public CalendarDayModel ClickedPeriod { get; } {
public CalendarItemTappedMessage(CalendarItemViewModel calendarItemViewModel, CalendarDayModel clickedPeriod)
{
CalendarItemViewModel = calendarItemViewModel;
ClickedPeriod = clickedPeriod;
} }
public CalendarItemViewModel CalendarItemViewModel { get; }
public CalendarDayModel ClickedPeriod { get; }
} }

View File

@@ -1,15 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<LangVersion>12</LangVersion> <Platforms>x86;x64;arm64</Platforms>
<Platforms>AnyCPU;x64;x86</Platforms> <RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
<AccelerateBuildsInVisualStudio>true</AccelerateBuildsInVisualStudio> <AccelerateBuildsInVisualStudio>true</AccelerateBuildsInVisualStudio>
<ProduceReferenceAssembly>true</ProduceReferenceAssembly> <ProduceReferenceAssembly>true</ProduceReferenceAssembly>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="TimePeriodLibrary.NET" Version="2.1.5" /> <PackageReference Include="TimePeriodLibrary.NET" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -1,308 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.12.35424.110
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wino.Core.Domain", "Wino.Core.Domain\Wino.Core.Domain.csproj", "{814400B6-5A05-4596-B451-3A116A147DC1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wino.Core.UWP", "Wino.Core.UWP\Wino.Core.UWP.csproj", "{395F19BA-1E42-495C-9DB5-1A6F537FCCB8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wino.Core.ViewModels", "Wino.Core.ViewModels\Wino.Core.ViewModels.csproj", "{510CD96C-B3FF-4EC9-A67B-845C842E6BEC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wino.Messaging", "Wino.Messages\Wino.Messaging.csproj", "{AB588CFD-4B0C-4A1F-B711-1999E3D092D0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wino.Server", "Wino.Server\Wino.Server.csproj", "{92DA33FC-9252-40C5-BF71-67ACB0B56F2B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wino.Core", "Wino.Core\Wino.Core.csproj", "{87FFCBF4-DC17-4F09-90D6-102CF4C72BAF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wino.Calendar", "Wino.Calendar\Wino.Calendar.csproj", "{600F4979-DB7E-409D-B7DA-B60BE4C55C35}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wino.SourceGenerators", "Wino.SourceGenerators\Wino.SourceGenerators.csproj", "{8A7EB697-D722-4E0F-B20E-9FC88373ADB5}"
EndProject
Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "Wino.Calendar.Packaging", "Wino.Calendar.Packaging\Wino.Calendar.Packaging.wapproj", "{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wino.Calendar.ViewModels", "Wino.Calendar.ViewModels\Wino.Calendar.ViewModels.csproj", "{CF850F8C-5042-4376-9CBA-C8F2BB554083}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wino.Services", "Wino.Services\Wino.Services.csproj", "{BBA49030-7277-48CF-B2FE-3D01CB6B6C81}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wino.Authentication", "Wino.Authentication\Wino.Authentication.csproj", "{16A979C2-F308-464F-9B2A-0AF8ED5EDB43}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|ARM = Debug|ARM
Debug|ARM64 = Debug|ARM64
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|ARM = Release|ARM
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{814400B6-5A05-4596-B451-3A116A147DC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{814400B6-5A05-4596-B451-3A116A147DC1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{814400B6-5A05-4596-B451-3A116A147DC1}.Debug|ARM.ActiveCfg = Debug|Any CPU
{814400B6-5A05-4596-B451-3A116A147DC1}.Debug|ARM.Build.0 = Debug|Any CPU
{814400B6-5A05-4596-B451-3A116A147DC1}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{814400B6-5A05-4596-B451-3A116A147DC1}.Debug|ARM64.Build.0 = Debug|Any CPU
{814400B6-5A05-4596-B451-3A116A147DC1}.Debug|x64.ActiveCfg = Debug|x64
{814400B6-5A05-4596-B451-3A116A147DC1}.Debug|x64.Build.0 = Debug|x64
{814400B6-5A05-4596-B451-3A116A147DC1}.Debug|x86.ActiveCfg = Debug|x86
{814400B6-5A05-4596-B451-3A116A147DC1}.Debug|x86.Build.0 = Debug|x86
{814400B6-5A05-4596-B451-3A116A147DC1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{814400B6-5A05-4596-B451-3A116A147DC1}.Release|Any CPU.Build.0 = Release|Any CPU
{814400B6-5A05-4596-B451-3A116A147DC1}.Release|ARM.ActiveCfg = Release|Any CPU
{814400B6-5A05-4596-B451-3A116A147DC1}.Release|ARM.Build.0 = Release|Any CPU
{814400B6-5A05-4596-B451-3A116A147DC1}.Release|ARM64.ActiveCfg = Release|Any CPU
{814400B6-5A05-4596-B451-3A116A147DC1}.Release|ARM64.Build.0 = Release|Any CPU
{814400B6-5A05-4596-B451-3A116A147DC1}.Release|x64.ActiveCfg = Release|x64
{814400B6-5A05-4596-B451-3A116A147DC1}.Release|x64.Build.0 = Release|x64
{814400B6-5A05-4596-B451-3A116A147DC1}.Release|x86.ActiveCfg = Release|x86
{814400B6-5A05-4596-B451-3A116A147DC1}.Release|x86.Build.0 = Release|x86
{395F19BA-1E42-495C-9DB5-1A6F537FCCB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{395F19BA-1E42-495C-9DB5-1A6F537FCCB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{395F19BA-1E42-495C-9DB5-1A6F537FCCB8}.Debug|ARM.ActiveCfg = Debug|Any CPU
{395F19BA-1E42-495C-9DB5-1A6F537FCCB8}.Debug|ARM.Build.0 = Debug|Any CPU
{395F19BA-1E42-495C-9DB5-1A6F537FCCB8}.Debug|ARM64.ActiveCfg = Debug|ARM64
{395F19BA-1E42-495C-9DB5-1A6F537FCCB8}.Debug|ARM64.Build.0 = Debug|ARM64
{395F19BA-1E42-495C-9DB5-1A6F537FCCB8}.Debug|x64.ActiveCfg = Debug|x64
{395F19BA-1E42-495C-9DB5-1A6F537FCCB8}.Debug|x64.Build.0 = Debug|x64
{395F19BA-1E42-495C-9DB5-1A6F537FCCB8}.Debug|x86.ActiveCfg = Debug|x86
{395F19BA-1E42-495C-9DB5-1A6F537FCCB8}.Debug|x86.Build.0 = Debug|x86
{395F19BA-1E42-495C-9DB5-1A6F537FCCB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{395F19BA-1E42-495C-9DB5-1A6F537FCCB8}.Release|Any CPU.Build.0 = Release|Any CPU
{395F19BA-1E42-495C-9DB5-1A6F537FCCB8}.Release|ARM.ActiveCfg = Release|Any CPU
{395F19BA-1E42-495C-9DB5-1A6F537FCCB8}.Release|ARM.Build.0 = Release|Any CPU
{395F19BA-1E42-495C-9DB5-1A6F537FCCB8}.Release|ARM64.ActiveCfg = Release|ARM64
{395F19BA-1E42-495C-9DB5-1A6F537FCCB8}.Release|ARM64.Build.0 = Release|ARM64
{395F19BA-1E42-495C-9DB5-1A6F537FCCB8}.Release|x64.ActiveCfg = Release|x64
{395F19BA-1E42-495C-9DB5-1A6F537FCCB8}.Release|x64.Build.0 = Release|x64
{395F19BA-1E42-495C-9DB5-1A6F537FCCB8}.Release|x86.ActiveCfg = Release|x86
{395F19BA-1E42-495C-9DB5-1A6F537FCCB8}.Release|x86.Build.0 = Release|x86
{510CD96C-B3FF-4EC9-A67B-845C842E6BEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{510CD96C-B3FF-4EC9-A67B-845C842E6BEC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{510CD96C-B3FF-4EC9-A67B-845C842E6BEC}.Debug|ARM.ActiveCfg = Debug|Any CPU
{510CD96C-B3FF-4EC9-A67B-845C842E6BEC}.Debug|ARM.Build.0 = Debug|Any CPU
{510CD96C-B3FF-4EC9-A67B-845C842E6BEC}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{510CD96C-B3FF-4EC9-A67B-845C842E6BEC}.Debug|ARM64.Build.0 = Debug|Any CPU
{510CD96C-B3FF-4EC9-A67B-845C842E6BEC}.Debug|x64.ActiveCfg = Debug|x64
{510CD96C-B3FF-4EC9-A67B-845C842E6BEC}.Debug|x64.Build.0 = Debug|x64
{510CD96C-B3FF-4EC9-A67B-845C842E6BEC}.Debug|x86.ActiveCfg = Debug|x86
{510CD96C-B3FF-4EC9-A67B-845C842E6BEC}.Debug|x86.Build.0 = Debug|x86
{510CD96C-B3FF-4EC9-A67B-845C842E6BEC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{510CD96C-B3FF-4EC9-A67B-845C842E6BEC}.Release|Any CPU.Build.0 = Release|Any CPU
{510CD96C-B3FF-4EC9-A67B-845C842E6BEC}.Release|ARM.ActiveCfg = Release|Any CPU
{510CD96C-B3FF-4EC9-A67B-845C842E6BEC}.Release|ARM.Build.0 = Release|Any CPU
{510CD96C-B3FF-4EC9-A67B-845C842E6BEC}.Release|ARM64.ActiveCfg = Release|Any CPU
{510CD96C-B3FF-4EC9-A67B-845C842E6BEC}.Release|ARM64.Build.0 = Release|Any CPU
{510CD96C-B3FF-4EC9-A67B-845C842E6BEC}.Release|x64.ActiveCfg = Release|x64
{510CD96C-B3FF-4EC9-A67B-845C842E6BEC}.Release|x64.Build.0 = Release|x64
{510CD96C-B3FF-4EC9-A67B-845C842E6BEC}.Release|x86.ActiveCfg = Release|x86
{510CD96C-B3FF-4EC9-A67B-845C842E6BEC}.Release|x86.Build.0 = Release|x86
{AB588CFD-4B0C-4A1F-B711-1999E3D092D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AB588CFD-4B0C-4A1F-B711-1999E3D092D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AB588CFD-4B0C-4A1F-B711-1999E3D092D0}.Debug|ARM.ActiveCfg = Debug|Any CPU
{AB588CFD-4B0C-4A1F-B711-1999E3D092D0}.Debug|ARM.Build.0 = Debug|Any CPU
{AB588CFD-4B0C-4A1F-B711-1999E3D092D0}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{AB588CFD-4B0C-4A1F-B711-1999E3D092D0}.Debug|ARM64.Build.0 = Debug|Any CPU
{AB588CFD-4B0C-4A1F-B711-1999E3D092D0}.Debug|x64.ActiveCfg = Debug|x64
{AB588CFD-4B0C-4A1F-B711-1999E3D092D0}.Debug|x64.Build.0 = Debug|x64
{AB588CFD-4B0C-4A1F-B711-1999E3D092D0}.Debug|x86.ActiveCfg = Debug|x86
{AB588CFD-4B0C-4A1F-B711-1999E3D092D0}.Debug|x86.Build.0 = Debug|x86
{AB588CFD-4B0C-4A1F-B711-1999E3D092D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AB588CFD-4B0C-4A1F-B711-1999E3D092D0}.Release|Any CPU.Build.0 = Release|Any CPU
{AB588CFD-4B0C-4A1F-B711-1999E3D092D0}.Release|ARM.ActiveCfg = Release|Any CPU
{AB588CFD-4B0C-4A1F-B711-1999E3D092D0}.Release|ARM.Build.0 = Release|Any CPU
{AB588CFD-4B0C-4A1F-B711-1999E3D092D0}.Release|ARM64.ActiveCfg = Release|Any CPU
{AB588CFD-4B0C-4A1F-B711-1999E3D092D0}.Release|ARM64.Build.0 = Release|Any CPU
{AB588CFD-4B0C-4A1F-B711-1999E3D092D0}.Release|x64.ActiveCfg = Release|x64
{AB588CFD-4B0C-4A1F-B711-1999E3D092D0}.Release|x64.Build.0 = Release|x64
{AB588CFD-4B0C-4A1F-B711-1999E3D092D0}.Release|x86.ActiveCfg = Release|x86
{AB588CFD-4B0C-4A1F-B711-1999E3D092D0}.Release|x86.Build.0 = Release|x86
{92DA33FC-9252-40C5-BF71-67ACB0B56F2B}.Debug|Any CPU.ActiveCfg = Debug|x64
{92DA33FC-9252-40C5-BF71-67ACB0B56F2B}.Debug|Any CPU.Build.0 = Debug|x64
{92DA33FC-9252-40C5-BF71-67ACB0B56F2B}.Debug|ARM.ActiveCfg = Debug|x64
{92DA33FC-9252-40C5-BF71-67ACB0B56F2B}.Debug|ARM.Build.0 = Debug|x64
{92DA33FC-9252-40C5-BF71-67ACB0B56F2B}.Debug|ARM64.ActiveCfg = Debug|ARM64
{92DA33FC-9252-40C5-BF71-67ACB0B56F2B}.Debug|ARM64.Build.0 = Debug|ARM64
{92DA33FC-9252-40C5-BF71-67ACB0B56F2B}.Debug|x64.ActiveCfg = Debug|x64
{92DA33FC-9252-40C5-BF71-67ACB0B56F2B}.Debug|x64.Build.0 = Debug|x64
{92DA33FC-9252-40C5-BF71-67ACB0B56F2B}.Debug|x86.ActiveCfg = Debug|x86
{92DA33FC-9252-40C5-BF71-67ACB0B56F2B}.Debug|x86.Build.0 = Debug|x86
{92DA33FC-9252-40C5-BF71-67ACB0B56F2B}.Release|Any CPU.ActiveCfg = Release|x64
{92DA33FC-9252-40C5-BF71-67ACB0B56F2B}.Release|Any CPU.Build.0 = Release|x64
{92DA33FC-9252-40C5-BF71-67ACB0B56F2B}.Release|ARM.ActiveCfg = Release|x64
{92DA33FC-9252-40C5-BF71-67ACB0B56F2B}.Release|ARM.Build.0 = Release|x64
{92DA33FC-9252-40C5-BF71-67ACB0B56F2B}.Release|ARM64.ActiveCfg = Release|ARM64
{92DA33FC-9252-40C5-BF71-67ACB0B56F2B}.Release|ARM64.Build.0 = Release|ARM64
{92DA33FC-9252-40C5-BF71-67ACB0B56F2B}.Release|x64.ActiveCfg = Release|x64
{92DA33FC-9252-40C5-BF71-67ACB0B56F2B}.Release|x64.Build.0 = Release|x64
{92DA33FC-9252-40C5-BF71-67ACB0B56F2B}.Release|x86.ActiveCfg = Release|x86
{92DA33FC-9252-40C5-BF71-67ACB0B56F2B}.Release|x86.Build.0 = Release|x86
{87FFCBF4-DC17-4F09-90D6-102CF4C72BAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{87FFCBF4-DC17-4F09-90D6-102CF4C72BAF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{87FFCBF4-DC17-4F09-90D6-102CF4C72BAF}.Debug|ARM.ActiveCfg = Debug|Any CPU
{87FFCBF4-DC17-4F09-90D6-102CF4C72BAF}.Debug|ARM.Build.0 = Debug|Any CPU
{87FFCBF4-DC17-4F09-90D6-102CF4C72BAF}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{87FFCBF4-DC17-4F09-90D6-102CF4C72BAF}.Debug|ARM64.Build.0 = Debug|Any CPU
{87FFCBF4-DC17-4F09-90D6-102CF4C72BAF}.Debug|x64.ActiveCfg = Debug|x64
{87FFCBF4-DC17-4F09-90D6-102CF4C72BAF}.Debug|x64.Build.0 = Debug|x64
{87FFCBF4-DC17-4F09-90D6-102CF4C72BAF}.Debug|x86.ActiveCfg = Debug|x86
{87FFCBF4-DC17-4F09-90D6-102CF4C72BAF}.Debug|x86.Build.0 = Debug|x86
{87FFCBF4-DC17-4F09-90D6-102CF4C72BAF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{87FFCBF4-DC17-4F09-90D6-102CF4C72BAF}.Release|Any CPU.Build.0 = Release|Any CPU
{87FFCBF4-DC17-4F09-90D6-102CF4C72BAF}.Release|ARM.ActiveCfg = Release|Any CPU
{87FFCBF4-DC17-4F09-90D6-102CF4C72BAF}.Release|ARM.Build.0 = Release|Any CPU
{87FFCBF4-DC17-4F09-90D6-102CF4C72BAF}.Release|ARM64.ActiveCfg = Release|Any CPU
{87FFCBF4-DC17-4F09-90D6-102CF4C72BAF}.Release|ARM64.Build.0 = Release|Any CPU
{87FFCBF4-DC17-4F09-90D6-102CF4C72BAF}.Release|x64.ActiveCfg = Release|x64
{87FFCBF4-DC17-4F09-90D6-102CF4C72BAF}.Release|x64.Build.0 = Release|x64
{87FFCBF4-DC17-4F09-90D6-102CF4C72BAF}.Release|x86.ActiveCfg = Release|x86
{87FFCBF4-DC17-4F09-90D6-102CF4C72BAF}.Release|x86.Build.0 = Release|x86
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Debug|Any CPU.ActiveCfg = Debug|x64
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Debug|Any CPU.Build.0 = Debug|x64
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Debug|Any CPU.Deploy.0 = Debug|x64
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Debug|ARM.ActiveCfg = Debug|ARM
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Debug|ARM.Build.0 = Debug|ARM
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Debug|ARM.Deploy.0 = Debug|ARM
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Debug|ARM64.ActiveCfg = Debug|ARM64
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Debug|ARM64.Build.0 = Debug|ARM64
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Debug|ARM64.Deploy.0 = Debug|ARM64
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Debug|x64.ActiveCfg = Debug|x64
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Debug|x64.Build.0 = Debug|x64
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Debug|x64.Deploy.0 = Debug|x64
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Debug|x86.ActiveCfg = Debug|x86
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Debug|x86.Build.0 = Debug|x86
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Debug|x86.Deploy.0 = Debug|x86
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Release|Any CPU.ActiveCfg = Release|x64
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Release|Any CPU.Build.0 = Release|x64
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Release|Any CPU.Deploy.0 = Release|x64
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Release|ARM.ActiveCfg = Release|ARM
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Release|ARM.Build.0 = Release|ARM
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Release|ARM.Deploy.0 = Release|ARM
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Release|ARM64.ActiveCfg = Release|ARM64
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Release|ARM64.Build.0 = Release|ARM64
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Release|ARM64.Deploy.0 = Release|ARM64
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Release|x64.ActiveCfg = Release|x64
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Release|x64.Build.0 = Release|x64
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Release|x64.Deploy.0 = Release|x64
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Release|x86.ActiveCfg = Release|x86
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Release|x86.Build.0 = Release|x86
{600F4979-DB7E-409D-B7DA-B60BE4C55C35}.Release|x86.Deploy.0 = Release|x86
{8A7EB697-D722-4E0F-B20E-9FC88373ADB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8A7EB697-D722-4E0F-B20E-9FC88373ADB5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8A7EB697-D722-4E0F-B20E-9FC88373ADB5}.Debug|ARM.ActiveCfg = Debug|Any CPU
{8A7EB697-D722-4E0F-B20E-9FC88373ADB5}.Debug|ARM.Build.0 = Debug|Any CPU
{8A7EB697-D722-4E0F-B20E-9FC88373ADB5}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{8A7EB697-D722-4E0F-B20E-9FC88373ADB5}.Debug|ARM64.Build.0 = Debug|Any CPU
{8A7EB697-D722-4E0F-B20E-9FC88373ADB5}.Debug|x64.ActiveCfg = Debug|Any CPU
{8A7EB697-D722-4E0F-B20E-9FC88373ADB5}.Debug|x64.Build.0 = Debug|Any CPU
{8A7EB697-D722-4E0F-B20E-9FC88373ADB5}.Debug|x86.ActiveCfg = Debug|Any CPU
{8A7EB697-D722-4E0F-B20E-9FC88373ADB5}.Debug|x86.Build.0 = Debug|Any CPU
{8A7EB697-D722-4E0F-B20E-9FC88373ADB5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8A7EB697-D722-4E0F-B20E-9FC88373ADB5}.Release|Any CPU.Build.0 = Release|Any CPU
{8A7EB697-D722-4E0F-B20E-9FC88373ADB5}.Release|ARM.ActiveCfg = Release|Any CPU
{8A7EB697-D722-4E0F-B20E-9FC88373ADB5}.Release|ARM.Build.0 = Release|Any CPU
{8A7EB697-D722-4E0F-B20E-9FC88373ADB5}.Release|ARM64.ActiveCfg = Release|Any CPU
{8A7EB697-D722-4E0F-B20E-9FC88373ADB5}.Release|ARM64.Build.0 = Release|Any CPU
{8A7EB697-D722-4E0F-B20E-9FC88373ADB5}.Release|x64.ActiveCfg = Release|Any CPU
{8A7EB697-D722-4E0F-B20E-9FC88373ADB5}.Release|x64.Build.0 = Release|Any CPU
{8A7EB697-D722-4E0F-B20E-9FC88373ADB5}.Release|x86.ActiveCfg = Release|Any CPU
{8A7EB697-D722-4E0F-B20E-9FC88373ADB5}.Release|x86.Build.0 = Release|Any CPU
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Debug|ARM.ActiveCfg = Debug|ARM
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Debug|ARM.Build.0 = Debug|ARM
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Debug|ARM.Deploy.0 = Debug|ARM
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Debug|ARM64.ActiveCfg = Debug|ARM64
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Debug|ARM64.Build.0 = Debug|ARM64
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Debug|ARM64.Deploy.0 = Debug|ARM64
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Debug|x64.ActiveCfg = Debug|x64
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Debug|x64.Build.0 = Debug|x64
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Debug|x64.Deploy.0 = Debug|x64
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Debug|x86.ActiveCfg = Debug|x86
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Debug|x86.Build.0 = Debug|x86
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Debug|x86.Deploy.0 = Debug|x86
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Release|Any CPU.Build.0 = Release|Any CPU
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Release|Any CPU.Deploy.0 = Release|Any CPU
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Release|ARM.ActiveCfg = Release|ARM
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Release|ARM.Build.0 = Release|ARM
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Release|ARM.Deploy.0 = Release|ARM
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Release|ARM64.ActiveCfg = Release|ARM64
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Release|ARM64.Build.0 = Release|ARM64
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Release|ARM64.Deploy.0 = Release|ARM64
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Release|x64.ActiveCfg = Release|x64
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Release|x64.Build.0 = Release|x64
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Release|x64.Deploy.0 = Release|x64
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Release|x86.ActiveCfg = Release|x86
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Release|x86.Build.0 = Release|x86
{7485B18C-F5AB-4ABE-BA7F-05B6623C67C8}.Release|x86.Deploy.0 = Release|x86
{CF850F8C-5042-4376-9CBA-C8F2BB554083}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CF850F8C-5042-4376-9CBA-C8F2BB554083}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CF850F8C-5042-4376-9CBA-C8F2BB554083}.Debug|ARM.ActiveCfg = Debug|Any CPU
{CF850F8C-5042-4376-9CBA-C8F2BB554083}.Debug|ARM.Build.0 = Debug|Any CPU
{CF850F8C-5042-4376-9CBA-C8F2BB554083}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{CF850F8C-5042-4376-9CBA-C8F2BB554083}.Debug|ARM64.Build.0 = Debug|Any CPU
{CF850F8C-5042-4376-9CBA-C8F2BB554083}.Debug|x64.ActiveCfg = Debug|x64
{CF850F8C-5042-4376-9CBA-C8F2BB554083}.Debug|x64.Build.0 = Debug|x64
{CF850F8C-5042-4376-9CBA-C8F2BB554083}.Debug|x86.ActiveCfg = Debug|x86
{CF850F8C-5042-4376-9CBA-C8F2BB554083}.Debug|x86.Build.0 = Debug|x86
{CF850F8C-5042-4376-9CBA-C8F2BB554083}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CF850F8C-5042-4376-9CBA-C8F2BB554083}.Release|Any CPU.Build.0 = Release|Any CPU
{CF850F8C-5042-4376-9CBA-C8F2BB554083}.Release|ARM.ActiveCfg = Release|Any CPU
{CF850F8C-5042-4376-9CBA-C8F2BB554083}.Release|ARM.Build.0 = Release|Any CPU
{CF850F8C-5042-4376-9CBA-C8F2BB554083}.Release|ARM64.ActiveCfg = Release|Any CPU
{CF850F8C-5042-4376-9CBA-C8F2BB554083}.Release|ARM64.Build.0 = Release|Any CPU
{CF850F8C-5042-4376-9CBA-C8F2BB554083}.Release|x64.ActiveCfg = Release|x64
{CF850F8C-5042-4376-9CBA-C8F2BB554083}.Release|x64.Build.0 = Release|x64
{CF850F8C-5042-4376-9CBA-C8F2BB554083}.Release|x86.ActiveCfg = Release|x86
{CF850F8C-5042-4376-9CBA-C8F2BB554083}.Release|x86.Build.0 = Release|x86
{BBA49030-7277-48CF-B2FE-3D01CB6B6C81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BBA49030-7277-48CF-B2FE-3D01CB6B6C81}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BBA49030-7277-48CF-B2FE-3D01CB6B6C81}.Debug|ARM.ActiveCfg = Debug|Any CPU
{BBA49030-7277-48CF-B2FE-3D01CB6B6C81}.Debug|ARM.Build.0 = Debug|Any CPU
{BBA49030-7277-48CF-B2FE-3D01CB6B6C81}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{BBA49030-7277-48CF-B2FE-3D01CB6B6C81}.Debug|ARM64.Build.0 = Debug|Any CPU
{BBA49030-7277-48CF-B2FE-3D01CB6B6C81}.Debug|x64.ActiveCfg = Debug|Any CPU
{BBA49030-7277-48CF-B2FE-3D01CB6B6C81}.Debug|x64.Build.0 = Debug|Any CPU
{BBA49030-7277-48CF-B2FE-3D01CB6B6C81}.Debug|x86.ActiveCfg = Debug|Any CPU
{BBA49030-7277-48CF-B2FE-3D01CB6B6C81}.Debug|x86.Build.0 = Debug|Any CPU
{BBA49030-7277-48CF-B2FE-3D01CB6B6C81}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BBA49030-7277-48CF-B2FE-3D01CB6B6C81}.Release|Any CPU.Build.0 = Release|Any CPU
{BBA49030-7277-48CF-B2FE-3D01CB6B6C81}.Release|ARM.ActiveCfg = Release|Any CPU
{BBA49030-7277-48CF-B2FE-3D01CB6B6C81}.Release|ARM.Build.0 = Release|Any CPU
{BBA49030-7277-48CF-B2FE-3D01CB6B6C81}.Release|ARM64.ActiveCfg = Release|Any CPU
{BBA49030-7277-48CF-B2FE-3D01CB6B6C81}.Release|ARM64.Build.0 = Release|Any CPU
{BBA49030-7277-48CF-B2FE-3D01CB6B6C81}.Release|x64.ActiveCfg = Release|Any CPU
{BBA49030-7277-48CF-B2FE-3D01CB6B6C81}.Release|x64.Build.0 = Release|Any CPU
{BBA49030-7277-48CF-B2FE-3D01CB6B6C81}.Release|x86.ActiveCfg = Release|Any CPU
{BBA49030-7277-48CF-B2FE-3D01CB6B6C81}.Release|x86.Build.0 = Release|Any CPU
{16A979C2-F308-464F-9B2A-0AF8ED5EDB43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{16A979C2-F308-464F-9B2A-0AF8ED5EDB43}.Debug|Any CPU.Build.0 = Debug|Any CPU
{16A979C2-F308-464F-9B2A-0AF8ED5EDB43}.Debug|ARM.ActiveCfg = Debug|Any CPU
{16A979C2-F308-464F-9B2A-0AF8ED5EDB43}.Debug|ARM.Build.0 = Debug|Any CPU
{16A979C2-F308-464F-9B2A-0AF8ED5EDB43}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{16A979C2-F308-464F-9B2A-0AF8ED5EDB43}.Debug|ARM64.Build.0 = Debug|Any CPU
{16A979C2-F308-464F-9B2A-0AF8ED5EDB43}.Debug|x64.ActiveCfg = Debug|x64
{16A979C2-F308-464F-9B2A-0AF8ED5EDB43}.Debug|x64.Build.0 = Debug|x64
{16A979C2-F308-464F-9B2A-0AF8ED5EDB43}.Debug|x86.ActiveCfg = Debug|x86
{16A979C2-F308-464F-9B2A-0AF8ED5EDB43}.Debug|x86.Build.0 = Debug|x86
{16A979C2-F308-464F-9B2A-0AF8ED5EDB43}.Release|Any CPU.ActiveCfg = Release|Any CPU
{16A979C2-F308-464F-9B2A-0AF8ED5EDB43}.Release|Any CPU.Build.0 = Release|Any CPU
{16A979C2-F308-464F-9B2A-0AF8ED5EDB43}.Release|ARM.ActiveCfg = Release|Any CPU
{16A979C2-F308-464F-9B2A-0AF8ED5EDB43}.Release|ARM.Build.0 = Release|Any CPU
{16A979C2-F308-464F-9B2A-0AF8ED5EDB43}.Release|ARM64.ActiveCfg = Release|Any CPU
{16A979C2-F308-464F-9B2A-0AF8ED5EDB43}.Release|ARM64.Build.0 = Release|Any CPU
{16A979C2-F308-464F-9B2A-0AF8ED5EDB43}.Release|x64.ActiveCfg = Release|x64
{16A979C2-F308-464F-9B2A-0AF8ED5EDB43}.Release|x64.Build.0 = Release|x64
{16A979C2-F308-464F-9B2A-0AF8ED5EDB43}.Release|x86.ActiveCfg = Release|x86
{16A979C2-F308-464F-9B2A-0AF8ED5EDB43}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -6,19 +6,18 @@ using Windows.UI.Xaml.Media.Animation;
using Wino.Activation; using Wino.Activation;
using Wino.Calendar.Views; using Wino.Calendar.Views;
namespace Wino.Calendar.Activation namespace Wino.Calendar.Activation;
public class DefaultActivationHandler : ActivationHandler<IActivatedEventArgs>
{ {
public class DefaultActivationHandler : ActivationHandler<IActivatedEventArgs> protected override Task HandleInternalAsync(IActivatedEventArgs args)
{ {
protected override Task HandleInternalAsync(IActivatedEventArgs args) (Window.Current.Content as Frame).Navigate(typeof(AppShell), null, new DrillInNavigationTransitionInfo());
{
(Window.Current.Content as Frame).Navigate(typeof(AppShell), null, new DrillInNavigationTransitionInfo());
return Task.CompletedTask; return Task.CompletedTask;
}
// Only navigate if Frame content doesn't exist.
protected override bool CanHandleInternal(IActivatedEventArgs args)
=> (Window.Current?.Content as Frame)?.Content == null;
} }
// Only navigate if Frame content doesn't exist.
protected override bool CanHandleInternal(IActivatedEventArgs args)
=> (Window.Current?.Content as Frame)?.Content == null;
} }

View File

@@ -24,141 +24,136 @@ using Wino.Messaging.Client.Connection;
using Wino.Messaging.Server; using Wino.Messaging.Server;
using Wino.Services; using Wino.Services;
namespace Wino.Calendar namespace Wino.Calendar;
public sealed partial class App : WinoApplication, IRecipient<NewCalendarSynchronizationRequested>
{ {
public sealed partial class App : WinoApplication, IRecipient<NewCalendarSynchronizationRequested> private BackgroundTaskDeferral connectionBackgroundTaskDeferral;
public App()
{ {
public override string AppCenterKey => "dfdad6ab-95f9-44cc-9112-45ec6730c49e"; InitializeComponent();
WeakReferenceMessenger.Default.Register<NewCalendarSynchronizationRequested>(this);
}
private BackgroundTaskDeferral connectionBackgroundTaskDeferral; public override IServiceProvider ConfigureServices()
private BackgroundTaskDeferral toastActionBackgroundTaskDeferral; {
var services = new ServiceCollection();
public App() services.RegisterSharedServices();
services.RegisterCalendarViewModelServices();
services.RegisterCoreUWPServices();
services.RegisterCoreViewModels();
RegisterUWPServices(services);
RegisterViewModels(services);
RegisterActivationHandlers(services);
return services.BuildServiceProvider();
}
#region Dependency Injection
private void RegisterActivationHandlers(IServiceCollection services)
{
//services.AddTransient<ProtocolActivationHandler>();
//services.AddTransient<ToastNotificationActivationHandler>();
//services.AddTransient<FileActivationHandler>();
}
private void RegisterUWPServices(IServiceCollection services)
{
services.AddSingleton<INavigationService, NavigationService>();
services.AddSingleton<ICalendarDialogService, DialogService>();
services.AddTransient<ISettingsBuilderService, SettingsBuilderService>();
services.AddTransient<IProviderService, ProviderService>();
services.AddSingleton<IAuthenticatorConfig, CalendarAuthenticatorConfig>();
services.AddSingleton<IAccountCalendarStateService, AccountCalendarStateService>();
}
private void RegisterViewModels(IServiceCollection services)
{
services.AddSingleton(typeof(AppShellViewModel));
services.AddSingleton(typeof(CalendarPageViewModel));
services.AddTransient(typeof(CalendarSettingsPageViewModel));
services.AddTransient(typeof(AccountManagementViewModel));
services.AddTransient(typeof(PersonalizationPageViewModel));
services.AddTransient(typeof(AccountDetailsPageViewModel));
services.AddTransient(typeof(EventDetailsPageViewModel));
}
#endregion
protected override void OnApplicationCloseRequested(object sender, SystemNavigationCloseRequestedPreviewEventArgs e)
{
// TODO: Check server running.
}
protected override async void OnLaunched(LaunchActivatedEventArgs args)
{
LogActivation($"OnLaunched -> {args.GetType().Name}, Kind -> {args.Kind}, PreviousExecutionState -> {args.PreviousExecutionState}, IsPrelaunch -> {args.PrelaunchActivated}");
if (!args.PrelaunchActivated)
{ {
InitializeComponent(); await ActivateWinoAsync(args);
WeakReferenceMessenger.Default.Register(this);
} }
}
public override IServiceProvider ConfigureServices() protected override IEnumerable<ActivationHandler> GetActivationHandlers()
{
return null;
}
protected override ActivationHandler<IActivatedEventArgs> GetDefaultActivationHandler()
=> new DefaultActivationHandler();
protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args)
{
base.OnBackgroundActivated(args);
if (args.TaskInstance.TriggerDetails is AppServiceTriggerDetails appServiceTriggerDetails)
{ {
var services = new ServiceCollection(); LogActivation("OnBackgroundActivated -> AppServiceTriggerDetails received.");
services.RegisterSharedServices(); // Only accept connections from callers in the same package
services.RegisterCalendarViewModelServices(); if (appServiceTriggerDetails.CallerPackageFamilyName == Package.Current.Id.FamilyName)
services.RegisterCoreUWPServices();
services.RegisterCoreViewModels();
RegisterUWPServices(services);
RegisterViewModels(services);
RegisterActivationHandlers(services);
return services.BuildServiceProvider();
}
#region Dependency Injection
private void RegisterActivationHandlers(IServiceCollection services)
{
//services.AddTransient<ProtocolActivationHandler>();
//services.AddTransient<ToastNotificationActivationHandler>();
//services.AddTransient<FileActivationHandler>();
}
private void RegisterUWPServices(IServiceCollection services)
{
services.AddSingleton<INavigationService, NavigationService>();
services.AddSingleton<ICalendarDialogService, DialogService>();
services.AddTransient<ISettingsBuilderService, SettingsBuilderService>();
services.AddTransient<IProviderService, ProviderService>();
services.AddSingleton<IAuthenticatorConfig, CalendarAuthenticatorConfig>();
services.AddSingleton<IAccountCalendarStateService, AccountCalendarStateService>();
}
private void RegisterViewModels(IServiceCollection services)
{
services.AddSingleton(typeof(AppShellViewModel));
services.AddSingleton(typeof(CalendarPageViewModel));
services.AddTransient(typeof(CalendarSettingsPageViewModel));
services.AddTransient(typeof(AccountManagementViewModel));
services.AddTransient(typeof(PersonalizationPageViewModel));
services.AddTransient(typeof(AccountDetailsPageViewModel));
services.AddTransient(typeof(EventDetailsPageViewModel));
}
#endregion
protected override void OnApplicationCloseRequested(object sender, SystemNavigationCloseRequestedPreviewEventArgs e)
{
// TODO: Check server running.
}
protected override async void OnLaunched(LaunchActivatedEventArgs args)
{
LogActivation($"OnLaunched -> {args.GetType().Name}, Kind -> {args.Kind}, PreviousExecutionState -> {args.PreviousExecutionState}, IsPrelaunch -> {args.PrelaunchActivated}");
if (!args.PrelaunchActivated)
{ {
await ActivateWinoAsync(args); // Connection established from the fulltrust process
}
}
protected override IEnumerable<ActivationHandler> GetActivationHandlers() connectionBackgroundTaskDeferral = args.TaskInstance.GetDeferral();
{ args.TaskInstance.Canceled += OnConnectionBackgroundTaskCanceled;
return null;
}
protected override ActivationHandler<IActivatedEventArgs> GetDefaultActivationHandler() AppServiceConnectionManager.Connection = appServiceTriggerDetails.AppServiceConnection;
=> new DefaultActivationHandler();
protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args) WeakReferenceMessenger.Default.Send(new WinoServerConnectionEstablished());
{
base.OnBackgroundActivated(args);
if (args.TaskInstance.TriggerDetails is AppServiceTriggerDetails appServiceTriggerDetails)
{
LogActivation("OnBackgroundActivated -> AppServiceTriggerDetails received.");
// Only accept connections from callers in the same package
if (appServiceTriggerDetails.CallerPackageFamilyName == Package.Current.Id.FamilyName)
{
// Connection established from the fulltrust process
connectionBackgroundTaskDeferral = args.TaskInstance.GetDeferral();
args.TaskInstance.Canceled += OnConnectionBackgroundTaskCanceled;
AppServiceConnectionManager.Connection = appServiceTriggerDetails.AppServiceConnection;
WeakReferenceMessenger.Default.Send(new WinoServerConnectionEstablished());
}
}
}
public void OnConnectionBackgroundTaskCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
sender.Canceled -= OnConnectionBackgroundTaskCanceled;
Log.Information($"Server connection background task was canceled. Reason: {reason}");
connectionBackgroundTaskDeferral?.Complete();
connectionBackgroundTaskDeferral = null;
AppServiceConnectionManager.Connection = null;
}
public async void Receive(NewCalendarSynchronizationRequested message)
{
try
{
var synchronizationResultResponse = await AppServiceConnectionManager.GetResponseAsync<CalendarSynchronizationResult, NewCalendarSynchronizationRequested>(message);
synchronizationResultResponse.ThrowIfFailed();
}
catch (WinoServerException serverException)
{
var dialogService = Services.GetService<ICalendarDialogService>();
dialogService.InfoBarMessage(Translator.Info_SyncFailedTitle, serverException.Message, InfoBarMessageType.Error);
} }
} }
} }
public void OnConnectionBackgroundTaskCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
sender.Canceled -= OnConnectionBackgroundTaskCanceled;
Log.Information($"Server connection background task was canceled. Reason: {reason}");
connectionBackgroundTaskDeferral?.Complete();
connectionBackgroundTaskDeferral = null;
AppServiceConnectionManager.Connection = null;
}
public async void Receive(NewCalendarSynchronizationRequested message)
{
try
{
var synchronizationResultResponse = await AppServiceConnectionManager.GetResponseAsync<CalendarSynchronizationResult, NewCalendarSynchronizationRequested>(message);
synchronizationResultResponse.ThrowIfFailed();
}
catch (WinoServerException serverException)
{
var dialogService = Services.GetService<ICalendarDialogService>();
dialogService.InfoBarMessage(Translator.Info_SyncFailedTitle, serverException.Message, InfoBarMessageType.Error);
}
}
} }

View File

@@ -1,41 +1,40 @@
using System; using System;
using Windows.Foundation; using Windows.Foundation;
namespace Wino.Calendar.Args namespace Wino.Calendar.Args;
/// <summary>
/// When a new timeline cell is selected.
/// </summary>
public class TimelineCellSelectedArgs : EventArgs
{ {
/// <summary> public TimelineCellSelectedArgs(DateTime clickedDate, Point canvasPoint, Point positionerPoint, Size cellSize)
/// When a new timeline cell is selected.
/// </summary>
public class TimelineCellSelectedArgs : EventArgs
{ {
public TimelineCellSelectedArgs(DateTime clickedDate, Point canvasPoint, Point positionerPoint, Size cellSize) ClickedDate = clickedDate;
{ CanvasPoint = canvasPoint;
ClickedDate = clickedDate; PositionerPoint = positionerPoint;
CanvasPoint = canvasPoint; CellSize = cellSize;
PositionerPoint = positionerPoint;
CellSize = cellSize;
}
/// <summary>
/// Clicked date and time information for the cell.
/// </summary>
public DateTime ClickedDate { get; set; }
/// <summary>
/// Position relative to the cell drawing part of the canvas.
/// Used to detect clicked cell from the position.
/// </summary>
public Point CanvasPoint { get; }
/// <summary>
/// Position relative to the main root positioner element of the drawing canvas.
/// Used to show the create event dialog teaching tip in correct position.
/// </summary>
public Point PositionerPoint { get; }
/// <summary>
/// Size of the cell.
/// </summary>
public Size CellSize { get; }
} }
/// <summary>
/// Clicked date and time information for the cell.
/// </summary>
public DateTime ClickedDate { get; set; }
/// <summary>
/// Position relative to the cell drawing part of the canvas.
/// Used to detect clicked cell from the position.
/// </summary>
public Point CanvasPoint { get; }
/// <summary>
/// Position relative to the main root positioner element of the drawing canvas.
/// Used to show the create event dialog teaching tip in correct position.
/// </summary>
public Point PositionerPoint { get; }
/// <summary>
/// Size of the cell.
/// </summary>
public Size CellSize { get; }
} }

View File

@@ -1,9 +1,8 @@
using System; using System;
namespace Wino.Calendar.Args namespace Wino.Calendar.Args;
{
/// <summary> /// <summary>
/// When selected timeline cell is unselected. /// When selected timeline cell is unselected.
/// </summary> /// </summary>
public class TimelineCellUnselectedArgs : EventArgs { } public class TimelineCellUnselectedArgs : EventArgs { }
}

View File

@@ -2,30 +2,29 @@
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Wino.Calendar.ViewModels.Data; using Wino.Calendar.ViewModels.Data;
namespace Wino.Calendar.Controls namespace Wino.Calendar.Controls;
public partial class CalendarItemCommandBarFlyout : CommandBarFlyout
{ {
public class CalendarItemCommandBarFlyout : CommandBarFlyout public static readonly DependencyProperty ItemProperty = DependencyProperty.Register(nameof(Item), typeof(CalendarItemViewModel), typeof(CalendarItemCommandBarFlyout), new PropertyMetadata(null, new PropertyChangedCallback(OnItemChanged)));
public CalendarItemViewModel Item
{ {
public static readonly DependencyProperty ItemProperty = DependencyProperty.Register(nameof(Item), typeof(CalendarItemViewModel), typeof(CalendarItemCommandBarFlyout), new PropertyMetadata(null, new PropertyChangedCallback(OnItemChanged))); get { return (CalendarItemViewModel)GetValue(ItemProperty); }
set { SetValue(ItemProperty, value); }
}
public CalendarItemViewModel Item
private static void OnItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is CalendarItemCommandBarFlyout flyout)
{ {
get { return (CalendarItemViewModel)GetValue(ItemProperty); } flyout.UpdateMenuItems();
set { SetValue(ItemProperty, value); }
}
private static void OnItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is CalendarItemCommandBarFlyout flyout)
{
flyout.UpdateMenuItems();
}
}
private void UpdateMenuItems()
{
} }
} }
private void UpdateMenuItems()
{
}
} }

View File

@@ -9,190 +9,189 @@ using Wino.Calendar.ViewModels.Messages;
using Wino.Core.Domain; using Wino.Core.Domain;
using Wino.Core.Domain.Models.Calendar; using Wino.Core.Domain.Models.Calendar;
namespace Wino.Calendar.Controls namespace Wino.Calendar.Controls;
public sealed partial class CalendarItemControl : UserControl
{ {
public sealed partial class CalendarItemControl : UserControl // Single tap has a delay to report double taps properly.
private bool isSingleTap = false;
public static readonly DependencyProperty CalendarItemProperty = DependencyProperty.Register(nameof(CalendarItem), typeof(CalendarItemViewModel), typeof(CalendarItemControl), new PropertyMetadata(null, new PropertyChangedCallback(OnCalendarItemChanged)));
public static readonly DependencyProperty IsDraggingProperty = DependencyProperty.Register(nameof(IsDragging), typeof(bool), typeof(CalendarItemControl), new PropertyMetadata(false));
public static readonly DependencyProperty IsCustomEventAreaProperty = DependencyProperty.Register(nameof(IsCustomEventArea), typeof(bool), typeof(CalendarItemControl), new PropertyMetadata(false));
public static readonly DependencyProperty CalendarItemTitleProperty = DependencyProperty.Register(nameof(CalendarItemTitle), typeof(string), typeof(CalendarItemControl), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty DisplayingDateProperty = DependencyProperty.Register(nameof(DisplayingDate), typeof(CalendarDayModel), typeof(CalendarItemControl), new PropertyMetadata(null, new PropertyChangedCallback(OnDisplayDateChanged)));
/// <summary>
/// Whether the control is displaying as regular event or all-multi day area in the day control.
/// </summary>
public bool IsCustomEventArea
{ {
// Single tap has a delay to report double taps properly. get { return (bool)GetValue(IsCustomEventAreaProperty); }
private bool isSingleTap = false; set { SetValue(IsCustomEventAreaProperty, value); }
}
public static readonly DependencyProperty CalendarItemProperty = DependencyProperty.Register(nameof(CalendarItem), typeof(CalendarItemViewModel), typeof(CalendarItemControl), new PropertyMetadata(null, new PropertyChangedCallback(OnCalendarItemChanged))); /// <summary>
public static readonly DependencyProperty IsDraggingProperty = DependencyProperty.Register(nameof(IsDragging), typeof(bool), typeof(CalendarItemControl), new PropertyMetadata(false)); /// Day that the calendar item is rendered at.
public static readonly DependencyProperty IsCustomEventAreaProperty = DependencyProperty.Register(nameof(IsCustomEventArea), typeof(bool), typeof(CalendarItemControl), new PropertyMetadata(false)); /// It's needed for title manipulation and some other adjustments later on.
public static readonly DependencyProperty CalendarItemTitleProperty = DependencyProperty.Register(nameof(CalendarItemTitle), typeof(string), typeof(CalendarItemControl), new PropertyMetadata(string.Empty)); /// </summary>
public static readonly DependencyProperty DisplayingDateProperty = DependencyProperty.Register(nameof(DisplayingDate), typeof(CalendarDayModel), typeof(CalendarItemControl), new PropertyMetadata(null, new PropertyChangedCallback(OnDisplayDateChanged))); public CalendarDayModel DisplayingDate
{
get { return (CalendarDayModel)GetValue(DisplayingDateProperty); }
set { SetValue(DisplayingDateProperty, value); }
}
/// <summary> public string CalendarItemTitle
/// Whether the control is displaying as regular event or all-multi day area in the day control. {
/// </summary> get { return (string)GetValue(CalendarItemTitleProperty); }
public bool IsCustomEventArea set { SetValue(CalendarItemTitleProperty, value); }
}
public CalendarItemViewModel CalendarItem
{
get { return (CalendarItemViewModel)GetValue(CalendarItemProperty); }
set { SetValue(CalendarItemProperty, value); }
}
public bool IsDragging
{
get { return (bool)GetValue(IsDraggingProperty); }
set { SetValue(IsDraggingProperty, value); }
}
public CalendarItemControl()
{
InitializeComponent();
}
private static void OnDisplayDateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is CalendarItemControl control)
{ {
get { return (bool)GetValue(IsCustomEventAreaProperty); } control.UpdateControlVisuals();
set { SetValue(IsCustomEventAreaProperty, value); }
} }
}
/// <summary> private static void OnCalendarItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
/// Day that the calendar item is rendered at. {
/// It's needed for title manipulation and some other adjustments later on. if (d is CalendarItemControl control)
/// </summary>
public CalendarDayModel DisplayingDate
{ {
get { return (CalendarDayModel)GetValue(DisplayingDateProperty); } control.UpdateControlVisuals();
set { SetValue(DisplayingDateProperty, value); }
} }
}
public string CalendarItemTitle private void UpdateControlVisuals()
{ {
get { return (string)GetValue(CalendarItemTitleProperty); } // Depending on the calendar item's duration and attributes, we might need to change the display title.
set { SetValue(CalendarItemTitleProperty, value); } // 1. Multi-Day events should display the start date and end date.
} // 2. Multi-Day events that occupy the whole day just shows 'all day'.
// 3. Other events should display the title.
public CalendarItemViewModel CalendarItem if (CalendarItem == null) return;
{ if (DisplayingDate == null) return;
get { return (CalendarItemViewModel)GetValue(CalendarItemProperty); }
set { SetValue(CalendarItemProperty, value); }
}
public bool IsDragging if (CalendarItem.IsMultiDayEvent)
{ {
get { return (bool)GetValue(IsDraggingProperty); } // Multi day events are divided into 3 categories:
set { SetValue(IsDraggingProperty, value); } // 1. All day events
} // 2. Events that started after the period.
// 3. Events that started before the period and finishes within the period.
public CalendarItemControl() var periodRelation = CalendarItem.Period.GetRelation(DisplayingDate.Period);
{
InitializeComponent();
}
private static void OnDisplayDateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) if (periodRelation == Itenso.TimePeriod.PeriodRelation.StartInside ||
{ periodRelation == PeriodRelation.EnclosingStartTouching)
if (d is CalendarItemControl control)
{ {
control.UpdateControlVisuals(); // hour -> title
CalendarItemTitle = $"{DisplayingDate.CalendarRenderOptions.CalendarSettings.GetTimeString(CalendarItem.StartDate.TimeOfDay)} -> {CalendarItem.Title}";
} }
} else if (
periodRelation == PeriodRelation.EndInside ||
private static void OnCalendarItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) periodRelation == PeriodRelation.EnclosingEndTouching)
{
if (d is CalendarItemControl control)
{ {
control.UpdateControlVisuals(); // title <- hour
CalendarItemTitle = $"{CalendarItem.Title} <- {DisplayingDate.CalendarRenderOptions.CalendarSettings.GetTimeString(CalendarItem.EndDate.TimeOfDay)}";
} }
} else if (periodRelation == PeriodRelation.Enclosing)
private void UpdateControlVisuals()
{
// Depending on the calendar item's duration and attributes, we might need to change the display title.
// 1. Multi-Day events should display the start date and end date.
// 2. Multi-Day events that occupy the whole day just shows 'all day'.
// 3. Other events should display the title.
if (CalendarItem == null) return;
if (DisplayingDate == null) return;
if (CalendarItem.IsMultiDayEvent)
{ {
// Multi day events are divided into 3 categories: // This event goes all day and it's multi-day.
// 1. All day events // Item must be hidden in the calendar but displayed on the custom area at the top.
// 2. Events that started after the period.
// 3. Events that started before the period and finishes within the period.
var periodRelation = CalendarItem.Period.GetRelation(DisplayingDate.Period); CalendarItemTitle = $"{Translator.CalendarItemAllDay} {CalendarItem.Title}";
if (periodRelation == Itenso.TimePeriod.PeriodRelation.StartInside ||
periodRelation == PeriodRelation.EnclosingStartTouching)
{
// hour -> title
CalendarItemTitle = $"{DisplayingDate.CalendarRenderOptions.CalendarSettings.GetTimeString(CalendarItem.StartDate.TimeOfDay)} -> {CalendarItem.Title}";
}
else if (
periodRelation == PeriodRelation.EndInside ||
periodRelation == PeriodRelation.EnclosingEndTouching)
{
// title <- hour
CalendarItemTitle = $"{CalendarItem.Title} <- {DisplayingDate.CalendarRenderOptions.CalendarSettings.GetTimeString(CalendarItem.EndDate.TimeOfDay)}";
}
else if (periodRelation == PeriodRelation.Enclosing)
{
// This event goes all day and it's multi-day.
// Item must be hidden in the calendar but displayed on the custom area at the top.
CalendarItemTitle = $"{Translator.CalendarItemAllDay} {CalendarItem.Title}";
}
else
{
// Not expected, but there it is.
CalendarItemTitle = CalendarItem.Title;
}
// Debug.WriteLine($"{CalendarItem.Title} Period relation with {DisplayingDate.Period.ToString()}: {periodRelation}");
} }
else else
{ {
// Not expected, but there it is.
CalendarItemTitle = CalendarItem.Title; CalendarItemTitle = CalendarItem.Title;
} }
UpdateVisualStates(); // Debug.WriteLine($"{CalendarItem.Title} Period relation with {DisplayingDate.Period.ToString()}: {periodRelation}");
}
else
{
CalendarItemTitle = CalendarItem.Title;
} }
private void UpdateVisualStates() UpdateVisualStates();
{ }
if (CalendarItem == null) return;
if (CalendarItem.IsAllDayEvent) private void UpdateVisualStates()
{
if (CalendarItem == null) return;
if (CalendarItem.IsAllDayEvent)
{
VisualStateManager.GoToState(this, "AllDayEvent", true);
}
else if (CalendarItem.IsMultiDayEvent)
{
if (IsCustomEventArea)
{ {
VisualStateManager.GoToState(this, "AllDayEvent", true); VisualStateManager.GoToState(this, "CustomAreaMultiDayEvent", true);
}
else if (CalendarItem.IsMultiDayEvent)
{
if (IsCustomEventArea)
{
VisualStateManager.GoToState(this, "CustomAreaMultiDayEvent", true);
}
else
{
// Hide it.
VisualStateManager.GoToState(this, "MultiDayEvent", true);
}
} }
else else
{ {
VisualStateManager.GoToState(this, "RegularEvent", true); // Hide it.
VisualStateManager.GoToState(this, "MultiDayEvent", true);
} }
} }
else
private void ControlDragStarting(UIElement sender, DragStartingEventArgs args) => IsDragging = true;
private void ControlDropped(UIElement sender, DropCompletedEventArgs args) => IsDragging = false;
private async void ControlTapped(object sender, TappedRoutedEventArgs e)
{ {
if (CalendarItem == null) return; VisualStateManager.GoToState(this, "RegularEvent", true);
isSingleTap = true;
await Task.Delay(100);
if (isSingleTap)
{
WeakReferenceMessenger.Default.Send(new CalendarItemTappedMessage(CalendarItem, DisplayingDate));
}
}
private void ControlDoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
{
if (CalendarItem == null) return;
isSingleTap = false;
WeakReferenceMessenger.Default.Send(new CalendarItemDoubleTappedMessage(CalendarItem));
}
private void ControlRightTapped(object sender, RightTappedRoutedEventArgs e)
{
if (CalendarItem == null) return;
WeakReferenceMessenger.Default.Send(new CalendarItemRightTappedMessage(CalendarItem));
} }
} }
private void ControlDragStarting(UIElement sender, DragStartingEventArgs args) => IsDragging = true;
private void ControlDropped(UIElement sender, DropCompletedEventArgs args) => IsDragging = false;
private async void ControlTapped(object sender, TappedRoutedEventArgs e)
{
if (CalendarItem == null) return;
isSingleTap = true;
await Task.Delay(100);
if (isSingleTap)
{
WeakReferenceMessenger.Default.Send(new CalendarItemTappedMessage(CalendarItem, DisplayingDate));
}
}
private void ControlDoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
{
if (CalendarItem == null) return;
isSingleTap = false;
WeakReferenceMessenger.Default.Send(new CalendarItemDoubleTappedMessage(CalendarItem));
}
private void ControlRightTapped(object sender, RightTappedRoutedEventArgs e)
{
if (CalendarItem == null) return;
WeakReferenceMessenger.Default.Send(new CalendarItemRightTappedMessage(CalendarItem));
}
} }

View File

@@ -1,43 +1,42 @@
using Windows.UI.Xaml.Automation.Peers; using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
namespace Wino.Calendar.Controls namespace Wino.Calendar.Controls;
/// <summary>
/// FlipView that hides the navigation buttons and exposes methods to navigate to the next and previous items with animations.
/// </summary>
public partial class CustomCalendarFlipView : FlipView
{ {
/// <summary> private const string PART_PreviousButton = "PreviousButtonHorizontal";
/// FlipView that hides the navigation buttons and exposes methods to navigate to the next and previous items with animations. private const string PART_NextButton = "NextButtonHorizontal";
/// </summary>
public class CustomCalendarFlipView : FlipView private Button PreviousButton;
private Button NextButton;
protected override void OnApplyTemplate()
{ {
private const string PART_PreviousButton = "PreviousButtonHorizontal"; base.OnApplyTemplate();
private const string PART_NextButton = "NextButtonHorizontal";
private Button PreviousButton; PreviousButton = GetTemplateChild(PART_PreviousButton) as Button;
private Button NextButton; NextButton = GetTemplateChild(PART_NextButton) as Button;
protected override void OnApplyTemplate() // Hide navigation buttons
{ PreviousButton.Opacity = NextButton.Opacity = 0;
base.OnApplyTemplate(); PreviousButton.IsHitTestVisible = NextButton.IsHitTestVisible = false;
PreviousButton = GetTemplateChild(PART_PreviousButton) as Button; var t = FindName("ScrollingHost");
NextButton = GetTemplateChild(PART_NextButton) as Button; }
// Hide navigation buttons public void GoPreviousFlip()
PreviousButton.Opacity = NextButton.Opacity = 0; {
PreviousButton.IsHitTestVisible = NextButton.IsHitTestVisible = false; var backPeer = new ButtonAutomationPeer(PreviousButton);
backPeer.Invoke();
}
var t = FindName("ScrollingHost"); public void GoNextFlip()
} {
var nextPeer = new ButtonAutomationPeer(NextButton);
public void GoPreviousFlip() nextPeer.Invoke();
{
var backPeer = new ButtonAutomationPeer(PreviousButton);
backPeer.Invoke();
}
public void GoNextFlip()
{
var nextPeer = new ButtonAutomationPeer(NextButton);
nextPeer.Invoke();
}
} }
} }

View File

@@ -3,76 +3,75 @@ using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Wino.Core.Domain.Models.Calendar; using Wino.Core.Domain.Models.Calendar;
namespace Wino.Calendar.Controls namespace Wino.Calendar.Controls;
public partial class DayColumnControl : Control
{ {
public class DayColumnControl : Control private const string PART_HeaderDateDayText = nameof(PART_HeaderDateDayText);
private const string PART_IsTodayBorder = nameof(PART_IsTodayBorder);
private const string PART_ColumnHeaderText = nameof(PART_ColumnHeaderText);
private const string PART_AllDayItemsControl = nameof(PART_AllDayItemsControl);
private const string TodayState = nameof(TodayState);
private const string NotTodayState = nameof(NotTodayState);
private TextBlock HeaderDateDayText;
private TextBlock ColumnHeaderText;
private Border IsTodayBorder;
private ItemsControl AllDayItemsControl;
public CalendarDayModel DayModel
{ {
private const string PART_HeaderDateDayText = nameof(PART_HeaderDateDayText); get { return (CalendarDayModel)GetValue(DayModelProperty); }
private const string PART_IsTodayBorder = nameof(PART_IsTodayBorder); set { SetValue(DayModelProperty, value); }
private const string PART_ColumnHeaderText = nameof(PART_ColumnHeaderText); }
private const string PART_AllDayItemsControl = nameof(PART_AllDayItemsControl); public static readonly DependencyProperty DayModelProperty = DependencyProperty.Register(nameof(DayModel), typeof(CalendarDayModel), typeof(DayColumnControl), new PropertyMetadata(null, new PropertyChangedCallback(OnRenderingPropertiesChanged)));
private const string TodayState = nameof(TodayState); public DayColumnControl()
private const string NotTodayState = nameof(NotTodayState); {
DefaultStyleKey = typeof(DayColumnControl);
}
private TextBlock HeaderDateDayText; protected override void OnApplyTemplate()
private TextBlock ColumnHeaderText; {
private Border IsTodayBorder; base.OnApplyTemplate();
private ItemsControl AllDayItemsControl;
public CalendarDayModel DayModel HeaderDateDayText = GetTemplateChild(PART_HeaderDateDayText) as TextBlock;
ColumnHeaderText = GetTemplateChild(PART_ColumnHeaderText) as TextBlock;
IsTodayBorder = GetTemplateChild(PART_IsTodayBorder) as Border;
AllDayItemsControl = GetTemplateChild(PART_AllDayItemsControl) as ItemsControl;
UpdateValues();
}
private static void OnRenderingPropertiesChanged(DependencyObject control, DependencyPropertyChangedEventArgs e)
{
if (control is DayColumnControl columnControl)
{ {
get { return (CalendarDayModel)GetValue(DayModelProperty); } columnControl.UpdateValues();
set { SetValue(DayModelProperty, value); }
}
public static readonly DependencyProperty DayModelProperty = DependencyProperty.Register(nameof(DayModel), typeof(CalendarDayModel), typeof(DayColumnControl), new PropertyMetadata(null, new PropertyChangedCallback(OnRenderingPropertiesChanged)));
public DayColumnControl()
{
DefaultStyleKey = typeof(DayColumnControl);
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
HeaderDateDayText = GetTemplateChild(PART_HeaderDateDayText) as TextBlock;
ColumnHeaderText = GetTemplateChild(PART_ColumnHeaderText) as TextBlock;
IsTodayBorder = GetTemplateChild(PART_IsTodayBorder) as Border;
AllDayItemsControl = GetTemplateChild(PART_AllDayItemsControl) as ItemsControl;
UpdateValues();
}
private static void OnRenderingPropertiesChanged(DependencyObject control, DependencyPropertyChangedEventArgs e)
{
if (control is DayColumnControl columnControl)
{
columnControl.UpdateValues();
}
}
private void UpdateValues()
{
if (HeaderDateDayText == null || IsTodayBorder == null || DayModel == null) return;
HeaderDateDayText.Text = DayModel.RepresentingDate.Day.ToString();
// Monthly template does not use it.
if (ColumnHeaderText != null)
{
ColumnHeaderText.Text = DayModel.RepresentingDate.ToString("dddd", DayModel.CalendarRenderOptions.CalendarSettings.CultureInfo);
}
AllDayItemsControl.ItemsSource = DayModel.EventsCollection.AllDayEvents;
bool isToday = DayModel.RepresentingDate.Date == DateTime.Now.Date;
VisualStateManager.GoToState(this, isToday ? TodayState : NotTodayState, false);
UpdateLayout();
} }
} }
private void UpdateValues()
{
if (HeaderDateDayText == null || IsTodayBorder == null || DayModel == null) return;
HeaderDateDayText.Text = DayModel.RepresentingDate.Day.ToString();
// Monthly template does not use it.
if (ColumnHeaderText != null)
{
ColumnHeaderText.Text = DayModel.RepresentingDate.ToString("dddd", DayModel.CalendarRenderOptions.CalendarSettings.CultureInfo);
}
AllDayItemsControl.ItemsSource = DayModel.EventsCollection.AllDayEvents;
bool isToday = DayModel.RepresentingDate.Date == DateTime.Now.Date;
VisualStateManager.GoToState(this, isToday ? TodayState : NotTodayState, false);
UpdateLayout();
}
} }

View File

@@ -3,55 +3,54 @@ using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Wino.Core.Domain.Enums; using Wino.Core.Domain.Enums;
namespace Wino.Calendar.Controls namespace Wino.Calendar.Controls;
public partial class DayHeaderControl : Control
{ {
public class DayHeaderControl : Control private const string PART_DayHeaderTextBlock = nameof(PART_DayHeaderTextBlock);
private TextBlock HeaderTextblock;
public DayHeaderDisplayType DisplayType
{ {
private const string PART_DayHeaderTextBlock = nameof(PART_DayHeaderTextBlock); get { return (DayHeaderDisplayType)GetValue(DisplayTypeProperty); }
private TextBlock HeaderTextblock; set { SetValue(DisplayTypeProperty, value); }
}
public DayHeaderDisplayType DisplayType public DateTime Date
{
get { return (DateTime)GetValue(DateProperty); }
set { SetValue(DateProperty, value); }
}
public static readonly DependencyProperty DateProperty = DependencyProperty.Register(nameof(Date), typeof(DateTime), typeof(DayHeaderControl), new PropertyMetadata(default(DateTime), new PropertyChangedCallback(OnHeaderPropertyChanged)));
public static readonly DependencyProperty DisplayTypeProperty = DependencyProperty.Register(nameof(DisplayType), typeof(DayHeaderDisplayType), typeof(DayHeaderControl), new PropertyMetadata(DayHeaderDisplayType.TwentyFourHour, new PropertyChangedCallback(OnHeaderPropertyChanged)));
public DayHeaderControl()
{
DefaultStyleKey = typeof(DayHeaderControl);
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
HeaderTextblock = GetTemplateChild(PART_DayHeaderTextBlock) as TextBlock;
UpdateHeaderText();
}
private static void OnHeaderPropertyChanged(DependencyObject control, DependencyPropertyChangedEventArgs e)
{
if (control is DayHeaderControl headerControl)
{ {
get { return (DayHeaderDisplayType)GetValue(DisplayTypeProperty); } headerControl.UpdateHeaderText();
set { SetValue(DisplayTypeProperty, value); }
} }
}
public DateTime Date private void UpdateHeaderText()
{
if (HeaderTextblock != null)
{ {
get { return (DateTime)GetValue(DateProperty); } HeaderTextblock.Text = DisplayType == DayHeaderDisplayType.TwelveHour ? Date.ToString("h tt") : Date.ToString("HH:mm");
set { SetValue(DateProperty, value); }
}
public static readonly DependencyProperty DateProperty = DependencyProperty.Register(nameof(Date), typeof(DateTime), typeof(DayHeaderControl), new PropertyMetadata(default(DateTime), new PropertyChangedCallback(OnHeaderPropertyChanged)));
public static readonly DependencyProperty DisplayTypeProperty = DependencyProperty.Register(nameof(DisplayType), typeof(DayHeaderDisplayType), typeof(DayHeaderControl), new PropertyMetadata(DayHeaderDisplayType.TwentyFourHour, new PropertyChangedCallback(OnHeaderPropertyChanged)));
public DayHeaderControl()
{
DefaultStyleKey = typeof(DayHeaderControl);
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
HeaderTextblock = GetTemplateChild(PART_DayHeaderTextBlock) as TextBlock;
UpdateHeaderText();
}
private static void OnHeaderPropertyChanged(DependencyObject control, DependencyPropertyChangedEventArgs e)
{
if (control is DayHeaderControl headerControl)
{
headerControl.UpdateHeaderText();
}
}
private void UpdateHeaderText()
{
if (HeaderTextblock != null)
{
HeaderTextblock.Text = DisplayType == DayHeaderDisplayType.TwelveHour ? Date.ToString("h tt") : Date.ToString("HH:mm");
}
} }
} }
} }

View File

@@ -10,291 +10,290 @@ using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Models.Calendar; using Wino.Core.Domain.Models.Calendar;
using Wino.Helpers; using Wino.Helpers;
namespace Wino.Calendar.Controls namespace Wino.Calendar.Controls;
public partial class WinoCalendarControl : Control
{ {
public class WinoCalendarControl : Control private const string PART_WinoFlipView = nameof(PART_WinoFlipView);
private const string PART_IdleGrid = nameof(PART_IdleGrid);
public event EventHandler<TimelineCellSelectedArgs> TimelineCellSelected;
public event EventHandler<TimelineCellUnselectedArgs> TimelineCellUnselected;
public event EventHandler ScrollPositionChanging;
#region Dependency Properties
public static readonly DependencyProperty DayRangesProperty = DependencyProperty.Register(nameof(DayRanges), typeof(ObservableCollection<DayRangeRenderModel>), typeof(WinoCalendarControl), new PropertyMetadata(null));
public static readonly DependencyProperty SelectedFlipViewIndexProperty = DependencyProperty.Register(nameof(SelectedFlipViewIndex), typeof(int), typeof(WinoCalendarControl), new PropertyMetadata(-1));
public static readonly DependencyProperty SelectedFlipViewDayRangeProperty = DependencyProperty.Register(nameof(SelectedFlipViewDayRange), typeof(DayRangeRenderModel), typeof(WinoCalendarControl), new PropertyMetadata(null));
public static readonly DependencyProperty ActiveCanvasProperty = DependencyProperty.Register(nameof(ActiveCanvas), typeof(WinoDayTimelineCanvas), typeof(WinoCalendarControl), new PropertyMetadata(null, new PropertyChangedCallback(OnActiveCanvasChanged)));
public static readonly DependencyProperty IsFlipIdleProperty = DependencyProperty.Register(nameof(IsFlipIdle), typeof(bool), typeof(WinoCalendarControl), new PropertyMetadata(true, new PropertyChangedCallback(OnIdleStateChanged)));
public static readonly DependencyProperty ActiveScrollViewerProperty = DependencyProperty.Register(nameof(ActiveScrollViewer), typeof(ScrollViewer), typeof(WinoCalendarControl), new PropertyMetadata(null, new PropertyChangedCallback(OnActiveVerticalScrollViewerChanged)));
public static readonly DependencyProperty VerticalItemsPanelTemplateProperty = DependencyProperty.Register(nameof(VerticalItemsPanelTemplate), typeof(ItemsPanelTemplate), typeof(WinoCalendarControl), new PropertyMetadata(null, new PropertyChangedCallback(OnCalendarOrientationPropertiesUpdated)));
public static readonly DependencyProperty HorizontalItemsPanelTemplateProperty = DependencyProperty.Register(nameof(HorizontalItemsPanelTemplate), typeof(ItemsPanelTemplate), typeof(WinoCalendarControl), new PropertyMetadata(null, new PropertyChangedCallback(OnCalendarOrientationPropertiesUpdated)));
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(nameof(Orientation), typeof(CalendarOrientation), typeof(WinoCalendarControl), new PropertyMetadata(CalendarOrientation.Horizontal, new PropertyChangedCallback(OnCalendarOrientationPropertiesUpdated)));
public static readonly DependencyProperty DisplayTypeProperty = DependencyProperty.Register(nameof(DisplayType), typeof(CalendarDisplayType), typeof(WinoCalendarControl), new PropertyMetadata(CalendarDisplayType.Day));
/// <summary>
/// Gets or sets the day-week-month-year display type.
/// Orientation is not determined by this property, but Orientation property.
/// This property is used to determine the template to use for the calendar.
/// </summary>
public CalendarDisplayType DisplayType
{ {
private const string PART_WinoFlipView = nameof(PART_WinoFlipView); get { return (CalendarDisplayType)GetValue(DisplayTypeProperty); }
private const string PART_IdleGrid = nameof(PART_IdleGrid); set { SetValue(DisplayTypeProperty, value); }
}
public event EventHandler<TimelineCellSelectedArgs> TimelineCellSelected; public CalendarOrientation Orientation
public event EventHandler<TimelineCellUnselectedArgs> TimelineCellUnselected; {
get { return (CalendarOrientation)GetValue(OrientationProperty); }
set { SetValue(OrientationProperty, value); }
}
public event EventHandler ScrollPositionChanging; public ItemsPanelTemplate VerticalItemsPanelTemplate
{
get { return (ItemsPanelTemplate)GetValue(VerticalItemsPanelTemplateProperty); }
set { SetValue(VerticalItemsPanelTemplateProperty, value); }
}
#region Dependency Properties public ItemsPanelTemplate HorizontalItemsPanelTemplate
{
get { return (ItemsPanelTemplate)GetValue(HorizontalItemsPanelTemplateProperty); }
set { SetValue(HorizontalItemsPanelTemplateProperty, value); }
}
public static readonly DependencyProperty DayRangesProperty = DependencyProperty.Register(nameof(DayRanges), typeof(ObservableCollection<DayRangeRenderModel>), typeof(WinoCalendarControl), new PropertyMetadata(null)); public DayRangeRenderModel SelectedFlipViewDayRange
public static readonly DependencyProperty SelectedFlipViewIndexProperty = DependencyProperty.Register(nameof(SelectedFlipViewIndex), typeof(int), typeof(WinoCalendarControl), new PropertyMetadata(-1)); {
public static readonly DependencyProperty SelectedFlipViewDayRangeProperty = DependencyProperty.Register(nameof(SelectedFlipViewDayRange), typeof(DayRangeRenderModel), typeof(WinoCalendarControl), new PropertyMetadata(null)); get { return (DayRangeRenderModel)GetValue(SelectedFlipViewDayRangeProperty); }
public static readonly DependencyProperty ActiveCanvasProperty = DependencyProperty.Register(nameof(ActiveCanvas), typeof(WinoDayTimelineCanvas), typeof(WinoCalendarControl), new PropertyMetadata(null, new PropertyChangedCallback(OnActiveCanvasChanged))); set { SetValue(SelectedFlipViewDayRangeProperty, value); }
public static readonly DependencyProperty IsFlipIdleProperty = DependencyProperty.Register(nameof(IsFlipIdle), typeof(bool), typeof(WinoCalendarControl), new PropertyMetadata(true, new PropertyChangedCallback(OnIdleStateChanged))); }
public static readonly DependencyProperty ActiveScrollViewerProperty = DependencyProperty.Register(nameof(ActiveScrollViewer), typeof(ScrollViewer), typeof(WinoCalendarControl), new PropertyMetadata(null, new PropertyChangedCallback(OnActiveVerticalScrollViewerChanged)));
public static readonly DependencyProperty VerticalItemsPanelTemplateProperty = DependencyProperty.Register(nameof(VerticalItemsPanelTemplate), typeof(ItemsPanelTemplate), typeof(WinoCalendarControl), new PropertyMetadata(null, new PropertyChangedCallback(OnCalendarOrientationPropertiesUpdated))); public ScrollViewer ActiveScrollViewer
public static readonly DependencyProperty HorizontalItemsPanelTemplateProperty = DependencyProperty.Register(nameof(HorizontalItemsPanelTemplate), typeof(ItemsPanelTemplate), typeof(WinoCalendarControl), new PropertyMetadata(null, new PropertyChangedCallback(OnCalendarOrientationPropertiesUpdated))); {
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(nameof(Orientation), typeof(CalendarOrientation), typeof(WinoCalendarControl), new PropertyMetadata(CalendarOrientation.Horizontal, new PropertyChangedCallback(OnCalendarOrientationPropertiesUpdated))); get { return (ScrollViewer)GetValue(ActiveScrollViewerProperty); }
public static readonly DependencyProperty DisplayTypeProperty = DependencyProperty.Register(nameof(DisplayType), typeof(CalendarDisplayType), typeof(WinoCalendarControl), new PropertyMetadata(CalendarDisplayType.Day)); set { SetValue(ActiveScrollViewerProperty, value); }
}
/// <summary> public WinoDayTimelineCanvas ActiveCanvas
/// Gets or sets the day-week-month-year display type. {
/// Orientation is not determined by this property, but Orientation property. get { return (WinoDayTimelineCanvas)GetValue(ActiveCanvasProperty); }
/// This property is used to determine the template to use for the calendar. set { SetValue(ActiveCanvasProperty, value); }
/// </summary> }
public CalendarDisplayType DisplayType
public bool IsFlipIdle
{
get { return (bool)GetValue(IsFlipIdleProperty); }
set { SetValue(IsFlipIdleProperty, value); }
}
/// <summary>
/// Gets or sets the collection of day ranges to render.
/// Each day range usually represents a week, but it may support other ranges.
/// </summary>
public ObservableCollection<DayRangeRenderModel> DayRanges
{
get { return (ObservableCollection<DayRangeRenderModel>)GetValue(DayRangesProperty); }
set { SetValue(DayRangesProperty, value); }
}
public int SelectedFlipViewIndex
{
get { return (int)GetValue(SelectedFlipViewIndexProperty); }
set { SetValue(SelectedFlipViewIndexProperty, value); }
}
#endregion
private WinoCalendarFlipView InternalFlipView;
private Grid IdleGrid;
public WinoCalendarControl()
{
DefaultStyleKey = typeof(WinoCalendarControl);
SizeChanged += CalendarSizeChanged;
}
private static void OnCalendarOrientationPropertiesUpdated(DependencyObject calendar, DependencyPropertyChangedEventArgs e)
{
if (calendar is WinoCalendarControl control)
{ {
get { return (CalendarDisplayType)GetValue(DisplayTypeProperty); } control.ManageCalendarOrientation();
set { SetValue(DisplayTypeProperty, value); }
}
public CalendarOrientation Orientation
{
get { return (CalendarOrientation)GetValue(OrientationProperty); }
set { SetValue(OrientationProperty, value); }
}
public ItemsPanelTemplate VerticalItemsPanelTemplate
{
get { return (ItemsPanelTemplate)GetValue(VerticalItemsPanelTemplateProperty); }
set { SetValue(VerticalItemsPanelTemplateProperty, value); }
}
public ItemsPanelTemplate HorizontalItemsPanelTemplate
{
get { return (ItemsPanelTemplate)GetValue(HorizontalItemsPanelTemplateProperty); }
set { SetValue(HorizontalItemsPanelTemplateProperty, value); }
}
public DayRangeRenderModel SelectedFlipViewDayRange
{
get { return (DayRangeRenderModel)GetValue(SelectedFlipViewDayRangeProperty); }
set { SetValue(SelectedFlipViewDayRangeProperty, value); }
}
public ScrollViewer ActiveScrollViewer
{
get { return (ScrollViewer)GetValue(ActiveScrollViewerProperty); }
set { SetValue(ActiveScrollViewerProperty, value); }
}
public WinoDayTimelineCanvas ActiveCanvas
{
get { return (WinoDayTimelineCanvas)GetValue(ActiveCanvasProperty); }
set { SetValue(ActiveCanvasProperty, value); }
}
public bool IsFlipIdle
{
get { return (bool)GetValue(IsFlipIdleProperty); }
set { SetValue(IsFlipIdleProperty, value); }
}
/// <summary>
/// Gets or sets the collection of day ranges to render.
/// Each day range usually represents a week, but it may support other ranges.
/// </summary>
public ObservableCollection<DayRangeRenderModel> DayRanges
{
get { return (ObservableCollection<DayRangeRenderModel>)GetValue(DayRangesProperty); }
set { SetValue(DayRangesProperty, value); }
}
public int SelectedFlipViewIndex
{
get { return (int)GetValue(SelectedFlipViewIndexProperty); }
set { SetValue(SelectedFlipViewIndexProperty, value); }
}
#endregion
private WinoCalendarFlipView InternalFlipView;
private Grid IdleGrid;
public WinoCalendarControl()
{
DefaultStyleKey = typeof(WinoCalendarControl);
SizeChanged += CalendarSizeChanged;
}
private static void OnCalendarOrientationPropertiesUpdated(DependencyObject calendar, DependencyPropertyChangedEventArgs e)
{
if (calendar is WinoCalendarControl control)
{
control.ManageCalendarOrientation();
}
}
private static void OnIdleStateChanged(DependencyObject calendar, DependencyPropertyChangedEventArgs e)
{
if (calendar is WinoCalendarControl calendarControl)
{
calendarControl.UpdateIdleState();
}
}
private static void OnActiveVerticalScrollViewerChanged(DependencyObject calendar, DependencyPropertyChangedEventArgs e)
{
if (calendar is WinoCalendarControl calendarControl)
{
if (e.OldValue is ScrollViewer oldScrollViewer)
{
calendarControl.DeregisterScrollChanges(oldScrollViewer);
}
if (e.NewValue is ScrollViewer newScrollViewer)
{
calendarControl.RegisterScrollChanges(newScrollViewer);
}
calendarControl.ManageHighlightedDateRange();
}
}
private static void OnActiveCanvasChanged(DependencyObject calendar, DependencyPropertyChangedEventArgs e)
{
if (calendar is WinoCalendarControl calendarControl)
{
if (e.OldValue is WinoDayTimelineCanvas oldCanvas)
{
// Dismiss any selection on the old canvas.
calendarControl.DeregisterCanvas(oldCanvas);
}
if (e.NewValue is WinoDayTimelineCanvas newCanvas)
{
calendarControl.RegisterCanvas(newCanvas);
}
calendarControl.ManageHighlightedDateRange();
}
}
private void ManageCalendarOrientation()
{
if (InternalFlipView == null || HorizontalItemsPanelTemplate == null || VerticalItemsPanelTemplate == null) return;
InternalFlipView.ItemsPanel = Orientation == CalendarOrientation.Horizontal ? HorizontalItemsPanelTemplate : VerticalItemsPanelTemplate;
}
private void ManageHighlightedDateRange()
=> SelectedFlipViewDayRange = InternalFlipView.SelectedItem as DayRangeRenderModel;
private void DeregisterCanvas(WinoDayTimelineCanvas canvas)
{
if (canvas == null) return;
canvas.SelectedDateTime = null;
canvas.TimelineCellSelected -= ActiveTimelineCellSelected;
canvas.TimelineCellUnselected -= ActiveTimelineCellUnselected;
}
private void RegisterCanvas(WinoDayTimelineCanvas canvas)
{
if (canvas == null) return;
canvas.SelectedDateTime = null;
canvas.TimelineCellSelected += ActiveTimelineCellSelected;
canvas.TimelineCellUnselected += ActiveTimelineCellUnselected;
}
private void RegisterScrollChanges(ScrollViewer scrollViewer)
{
if (scrollViewer == null) return;
scrollViewer.ViewChanging += ScrollViewChanging;
}
private void DeregisterScrollChanges(ScrollViewer scrollViewer)
{
if (scrollViewer == null) return;
scrollViewer.ViewChanging -= ScrollViewChanging;
}
private void ScrollViewChanging(object sender, ScrollViewerViewChangingEventArgs e)
=> ScrollPositionChanging?.Invoke(this, EventArgs.Empty);
private void CalendarSizeChanged(object sender, SizeChangedEventArgs e)
{
if (ActiveCanvas == null) return;
ActiveCanvas.SelectedDateTime = null;
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
InternalFlipView = GetTemplateChild(PART_WinoFlipView) as WinoCalendarFlipView;
IdleGrid = GetTemplateChild(PART_IdleGrid) as Grid;
UpdateIdleState();
ManageCalendarOrientation();
}
private void UpdateIdleState()
{
InternalFlipView.Opacity = IsFlipIdle ? 0 : 1;
IdleGrid.Visibility = IsFlipIdle ? Visibility.Visible : Visibility.Collapsed;
}
private void ActiveTimelineCellUnselected(object sender, TimelineCellUnselectedArgs e)
=> TimelineCellUnselected?.Invoke(this, e);
private void ActiveTimelineCellSelected(object sender, TimelineCellSelectedArgs e)
=> TimelineCellSelected?.Invoke(this, e);
public void NavigateToDay(DateTime dateTime) => InternalFlipView.NavigateToDay(dateTime);
public async void NavigateToHour(TimeSpan timeSpan)
{
if (ActiveScrollViewer == null) return;
// Total height of the FlipViewItem is the same as vertical ScrollViewer to position day headers.
await Task.Yield();
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, () =>
{
double hourHeght = 60;
double totalHeight = ActiveScrollViewer.ScrollableHeight;
double scrollPosition = timeSpan.TotalHours * hourHeght;
ActiveScrollViewer.ChangeView(null, scrollPosition, null, disableAnimation: false);
});
}
public void ResetTimelineSelection()
{
if (ActiveCanvas == null) return;
ActiveCanvas.SelectedDateTime = null;
}
public void GoNextRange()
{
if (InternalFlipView == null) return;
InternalFlipView.GoNextFlip();
}
public void GoPreviousRange()
{
if (InternalFlipView == null) return;
InternalFlipView.GoPreviousFlip();
}
public void UnselectActiveTimelineCell()
{
if (ActiveCanvas == null) return;
ActiveCanvas.SelectedDateTime = null;
}
public CalendarItemControl GetCalendarItemControl(CalendarItemViewModel calendarItemViewModel)
{
return this.FindDescendants<CalendarItemControl>().FirstOrDefault(a => a.CalendarItem == calendarItemViewModel);
} }
} }
private static void OnIdleStateChanged(DependencyObject calendar, DependencyPropertyChangedEventArgs e)
{
if (calendar is WinoCalendarControl calendarControl)
{
calendarControl.UpdateIdleState();
}
}
private static void OnActiveVerticalScrollViewerChanged(DependencyObject calendar, DependencyPropertyChangedEventArgs e)
{
if (calendar is WinoCalendarControl calendarControl)
{
if (e.OldValue is ScrollViewer oldScrollViewer)
{
calendarControl.DeregisterScrollChanges(oldScrollViewer);
}
if (e.NewValue is ScrollViewer newScrollViewer)
{
calendarControl.RegisterScrollChanges(newScrollViewer);
}
calendarControl.ManageHighlightedDateRange();
}
}
private static void OnActiveCanvasChanged(DependencyObject calendar, DependencyPropertyChangedEventArgs e)
{
if (calendar is WinoCalendarControl calendarControl)
{
if (e.OldValue is WinoDayTimelineCanvas oldCanvas)
{
// Dismiss any selection on the old canvas.
calendarControl.DeregisterCanvas(oldCanvas);
}
if (e.NewValue is WinoDayTimelineCanvas newCanvas)
{
calendarControl.RegisterCanvas(newCanvas);
}
calendarControl.ManageHighlightedDateRange();
}
}
private void ManageCalendarOrientation()
{
if (InternalFlipView == null || HorizontalItemsPanelTemplate == null || VerticalItemsPanelTemplate == null) return;
InternalFlipView.ItemsPanel = Orientation == CalendarOrientation.Horizontal ? HorizontalItemsPanelTemplate : VerticalItemsPanelTemplate;
}
private void ManageHighlightedDateRange()
=> SelectedFlipViewDayRange = InternalFlipView.SelectedItem as DayRangeRenderModel;
private void DeregisterCanvas(WinoDayTimelineCanvas canvas)
{
if (canvas == null) return;
canvas.SelectedDateTime = null;
canvas.TimelineCellSelected -= ActiveTimelineCellSelected;
canvas.TimelineCellUnselected -= ActiveTimelineCellUnselected;
}
private void RegisterCanvas(WinoDayTimelineCanvas canvas)
{
if (canvas == null) return;
canvas.SelectedDateTime = null;
canvas.TimelineCellSelected += ActiveTimelineCellSelected;
canvas.TimelineCellUnselected += ActiveTimelineCellUnselected;
}
private void RegisterScrollChanges(ScrollViewer scrollViewer)
{
if (scrollViewer == null) return;
scrollViewer.ViewChanging += ScrollViewChanging;
}
private void DeregisterScrollChanges(ScrollViewer scrollViewer)
{
if (scrollViewer == null) return;
scrollViewer.ViewChanging -= ScrollViewChanging;
}
private void ScrollViewChanging(object sender, ScrollViewerViewChangingEventArgs e)
=> ScrollPositionChanging?.Invoke(this, EventArgs.Empty);
private void CalendarSizeChanged(object sender, SizeChangedEventArgs e)
{
if (ActiveCanvas == null) return;
ActiveCanvas.SelectedDateTime = null;
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
InternalFlipView = GetTemplateChild(PART_WinoFlipView) as WinoCalendarFlipView;
IdleGrid = GetTemplateChild(PART_IdleGrid) as Grid;
UpdateIdleState();
ManageCalendarOrientation();
}
private void UpdateIdleState()
{
InternalFlipView.Opacity = IsFlipIdle ? 0 : 1;
IdleGrid.Visibility = IsFlipIdle ? Visibility.Visible : Visibility.Collapsed;
}
private void ActiveTimelineCellUnselected(object sender, TimelineCellUnselectedArgs e)
=> TimelineCellUnselected?.Invoke(this, e);
private void ActiveTimelineCellSelected(object sender, TimelineCellSelectedArgs e)
=> TimelineCellSelected?.Invoke(this, e);
public void NavigateToDay(DateTime dateTime) => InternalFlipView.NavigateToDay(dateTime);
public async void NavigateToHour(TimeSpan timeSpan)
{
if (ActiveScrollViewer == null) return;
// Total height of the FlipViewItem is the same as vertical ScrollViewer to position day headers.
await Task.Yield();
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, () =>
{
double hourHeght = 60;
double totalHeight = ActiveScrollViewer.ScrollableHeight;
double scrollPosition = timeSpan.TotalHours * hourHeght;
ActiveScrollViewer.ChangeView(null, scrollPosition, null, disableAnimation: false);
});
}
public void ResetTimelineSelection()
{
if (ActiveCanvas == null) return;
ActiveCanvas.SelectedDateTime = null;
}
public void GoNextRange()
{
if (InternalFlipView == null) return;
InternalFlipView.GoNextFlip();
}
public void GoPreviousRange()
{
if (InternalFlipView == null) return;
InternalFlipView.GoPreviousFlip();
}
public void UnselectActiveTimelineCell()
{
if (ActiveCanvas == null) return;
ActiveCanvas.SelectedDateTime = null;
}
public CalendarItemControl GetCalendarItemControl(CalendarItemViewModel calendarItemViewModel)
{
return this.FindDescendants<CalendarItemControl>().FirstOrDefault(a => a.CalendarItem == calendarItemViewModel);
}
} }

View File

@@ -8,179 +8,178 @@ using Windows.UI.Xaml.Controls;
using Wino.Core.Domain.Collections; using Wino.Core.Domain.Collections;
using Wino.Core.Domain.Models.Calendar; using Wino.Core.Domain.Models.Calendar;
namespace Wino.Calendar.Controls namespace Wino.Calendar.Controls;
public partial class WinoCalendarFlipView : CustomCalendarFlipView
{ {
public class WinoCalendarFlipView : CustomCalendarFlipView public static readonly DependencyProperty IsIdleProperty = DependencyProperty.Register(nameof(IsIdle), typeof(bool), typeof(WinoCalendarFlipView), new PropertyMetadata(true));
public static readonly DependencyProperty ActiveCanvasProperty = DependencyProperty.Register(nameof(ActiveCanvas), typeof(WinoDayTimelineCanvas), typeof(WinoCalendarFlipView), new PropertyMetadata(null));
public static readonly DependencyProperty ActiveVerticalScrollViewerProperty = DependencyProperty.Register(nameof(ActiveVerticalScrollViewer), typeof(ScrollViewer), typeof(WinoCalendarFlipView), new PropertyMetadata(null));
/// <summary>
/// Gets or sets the active canvas that is currently displayed in the flip view.
/// Each day-range of flip view item has a canvas that displays the day timeline.
/// </summary>
public WinoDayTimelineCanvas ActiveCanvas
{ {
public static readonly DependencyProperty IsIdleProperty = DependencyProperty.Register(nameof(IsIdle), typeof(bool), typeof(WinoCalendarFlipView), new PropertyMetadata(true)); get { return (WinoDayTimelineCanvas)GetValue(ActiveCanvasProperty); }
public static readonly DependencyProperty ActiveCanvasProperty = DependencyProperty.Register(nameof(ActiveCanvas), typeof(WinoDayTimelineCanvas), typeof(WinoCalendarFlipView), new PropertyMetadata(null)); set { SetValue(ActiveCanvasProperty, value); }
public static readonly DependencyProperty ActiveVerticalScrollViewerProperty = DependencyProperty.Register(nameof(ActiveVerticalScrollViewer), typeof(ScrollViewer), typeof(WinoCalendarFlipView), new PropertyMetadata(null)); }
/// <summary> /// <summary>
/// Gets or sets the active canvas that is currently displayed in the flip view. /// Gets or sets the scroll viewer that is currently active in the flip view.
/// Each day-range of flip view item has a canvas that displays the day timeline. /// It's the vertical scroll that scrolls the timeline only, not the header part that belongs
/// </summary> /// to parent FlipView control.
public WinoDayTimelineCanvas ActiveCanvas /// </summary>
public ScrollViewer ActiveVerticalScrollViewer
{
get { return (ScrollViewer)GetValue(ActiveVerticalScrollViewerProperty); }
set { SetValue(ActiveVerticalScrollViewerProperty, value); }
}
public bool IsIdle
{
get { return (bool)GetValue(IsIdleProperty); }
set { SetValue(IsIdleProperty, value); }
}
public WinoCalendarFlipView()
{
RegisterPropertyChangedCallback(SelectedIndexProperty, new DependencyPropertyChangedCallback(OnSelectedIndexUpdated));
RegisterPropertyChangedCallback(ItemsSourceProperty, new DependencyPropertyChangedCallback(OnItemsSourceChanged));
}
private static void OnItemsSourceChanged(DependencyObject d, DependencyProperty e)
{
if (d is WinoCalendarFlipView flipView)
{ {
get { return (WinoDayTimelineCanvas)GetValue(ActiveCanvasProperty); } flipView.RegisterItemsSourceChange();
set { SetValue(ActiveCanvasProperty, value); } }
}
private static void OnSelectedIndexUpdated(DependencyObject d, DependencyProperty e)
{
if (d is WinoCalendarFlipView flipView)
{
flipView.UpdateActiveCanvas();
flipView.UpdateActiveScrollViewer();
}
}
private void RegisterItemsSourceChange()
{
if (GetItemsSource() is INotifyCollectionChanged notifyCollectionChanged)
{
notifyCollectionChanged.CollectionChanged += ItemsSourceUpdated;
}
}
private void ItemsSourceUpdated(object sender, NotifyCollectionChangedEventArgs e)
{
IsIdle = e.Action == NotifyCollectionChangedAction.Reset || e.Action == NotifyCollectionChangedAction.Replace;
}
private async Task<FlipViewItem> GetCurrentFlipViewItem()
{
// TODO: Refactor this mechanism by listening to PrepareContainerForItemOverride and Loaded events together.
while (ContainerFromIndex(SelectedIndex) == null)
{
await Task.Delay(100);
} }
/// <summary> return ContainerFromIndex(SelectedIndex) as FlipViewItem;
/// Gets or sets the scroll viewer that is currently active in the flip view.
/// It's the vertical scroll that scrolls the timeline only, not the header part that belongs
/// to parent FlipView control.
/// </summary>
public ScrollViewer ActiveVerticalScrollViewer
{
get { return (ScrollViewer)GetValue(ActiveVerticalScrollViewerProperty); }
set { SetValue(ActiveVerticalScrollViewerProperty, value); }
}
public bool IsIdle
{
get { return (bool)GetValue(IsIdleProperty); }
set { SetValue(IsIdleProperty, value); }
}
public WinoCalendarFlipView() }
{
RegisterPropertyChangedCallback(SelectedIndexProperty, new DependencyPropertyChangedCallback(OnSelectedIndexUpdated));
RegisterPropertyChangedCallback(ItemsSourceProperty, new DependencyPropertyChangedCallback(OnItemsSourceChanged));
}
private static void OnItemsSourceChanged(DependencyObject d, DependencyProperty e) private void UpdateActiveScrollViewer()
{
if (SelectedIndex < 0)
ActiveVerticalScrollViewer = null;
else
{ {
if (d is WinoCalendarFlipView flipView) GetCurrentFlipViewItem().ContinueWith(task =>
{ {
flipView.RegisterItemsSourceChange(); if (task.IsCompletedSuccessfully)
}
}
private static void OnSelectedIndexUpdated(DependencyObject d, DependencyProperty e)
{
if (d is WinoCalendarFlipView flipView)
{
flipView.UpdateActiveCanvas();
flipView.UpdateActiveScrollViewer();
}
}
private void RegisterItemsSourceChange()
{
if (GetItemsSource() is INotifyCollectionChanged notifyCollectionChanged)
{
notifyCollectionChanged.CollectionChanged += ItemsSourceUpdated;
}
}
private void ItemsSourceUpdated(object sender, NotifyCollectionChangedEventArgs e)
{
IsIdle = e.Action == NotifyCollectionChangedAction.Reset || e.Action == NotifyCollectionChangedAction.Replace;
}
private async Task<FlipViewItem> GetCurrentFlipViewItem()
{
// TODO: Refactor this mechanism by listening to PrepareContainerForItemOverride and Loaded events together.
while (ContainerFromIndex(SelectedIndex) == null)
{
await Task.Delay(100);
}
return ContainerFromIndex(SelectedIndex) as FlipViewItem;
}
private void UpdateActiveScrollViewer()
{
if (SelectedIndex < 0)
ActiveVerticalScrollViewer = null;
else
{
GetCurrentFlipViewItem().ContinueWith(task =>
{ {
if (task.IsCompletedSuccessfully) var flipViewItem = task.Result;
_ = Dispatcher.TryRunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{ {
var flipViewItem = task.Result; ActiveVerticalScrollViewer = flipViewItem.FindDescendant<ScrollViewer>();
});
_ = Dispatcher.TryRunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
ActiveVerticalScrollViewer = flipViewItem.FindDescendant<ScrollViewer>();
});
}
});
}
}
public void UpdateActiveCanvas()
{
if (SelectedIndex < 0)
ActiveCanvas = null;
else
{
GetCurrentFlipViewItem().ContinueWith(task =>
{
if (task.IsCompletedSuccessfully)
{
var flipViewItem = task.Result;
_ = Dispatcher.TryRunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
ActiveCanvas = flipViewItem.FindDescendant<WinoDayTimelineCanvas>();
});
}
});
}
}
/// <summary>
/// Navigates to the specified date in the calendar.
/// </summary>
/// <param name="dateTime">Date to navigate.</param>
public async void NavigateToDay(DateTime dateTime)
{
await Task.Yield();
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, () =>
{
// Find the day range that contains the date.
var dayRange = GetItemsSource()?.FirstOrDefault(a => a.CalendarDays.Any(b => b.RepresentingDate.Date == dateTime.Date));
if (dayRange != null)
{
var navigationItemIndex = GetItemsSource().IndexOf(dayRange);
if (Math.Abs(navigationItemIndex - SelectedIndex) > 4)
{
// Difference between dates are high.
// No need to animate this much, just go without animating.
SelectedIndex = navigationItemIndex;
}
else
{
// Until we reach the day in the flip, simulate next-prev button clicks.
// This will make sure the FlipView animations are triggered.
// Setting SelectedIndex directly doesn't trigger the animations.
while (SelectedIndex != navigationItemIndex)
{
if (SelectedIndex > navigationItemIndex)
{
GoPreviousFlip();
}
else
{
GoNextFlip();
}
}
}
} }
}); });
} }
private ObservableRangeCollection<DayRangeRenderModel> GetItemsSource()
=> ItemsSource as ObservableRangeCollection<DayRangeRenderModel>;
} }
public void UpdateActiveCanvas()
{
if (SelectedIndex < 0)
ActiveCanvas = null;
else
{
GetCurrentFlipViewItem().ContinueWith(task =>
{
if (task.IsCompletedSuccessfully)
{
var flipViewItem = task.Result;
_ = Dispatcher.TryRunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
ActiveCanvas = flipViewItem.FindDescendant<WinoDayTimelineCanvas>();
});
}
});
}
}
/// <summary>
/// Navigates to the specified date in the calendar.
/// </summary>
/// <param name="dateTime">Date to navigate.</param>
public async void NavigateToDay(DateTime dateTime)
{
await Task.Yield();
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, () =>
{
// Find the day range that contains the date.
var dayRange = GetItemsSource()?.FirstOrDefault(a => a.CalendarDays.Any(b => b.RepresentingDate.Date == dateTime.Date));
if (dayRange != null)
{
var navigationItemIndex = GetItemsSource().IndexOf(dayRange);
if (Math.Abs(navigationItemIndex - SelectedIndex) > 4)
{
// Difference between dates are high.
// No need to animate this much, just go without animating.
SelectedIndex = navigationItemIndex;
}
else
{
// Until we reach the day in the flip, simulate next-prev button clicks.
// This will make sure the FlipView animations are triggered.
// Setting SelectedIndex directly doesn't trigger the animations.
while (SelectedIndex != navigationItemIndex)
{
if (SelectedIndex > navigationItemIndex)
{
GoPreviousFlip();
}
else
{
GoNextFlip();
}
}
}
}
});
}
private ObservableRangeCollection<DayRangeRenderModel> GetItemsSource()
=> ItemsSource as ObservableRangeCollection<DayRangeRenderModel>;
} }

View File

@@ -11,284 +11,283 @@ using Wino.Calendar.Models;
using Wino.Calendar.ViewModels.Data; using Wino.Calendar.ViewModels.Data;
using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Interfaces;
namespace Wino.Calendar.Controls namespace Wino.Calendar.Controls;
public partial class WinoCalendarPanel : Panel
{ {
public class WinoCalendarPanel : Panel private const double LastItemRightExtraMargin = 12d;
// Store each ICalendarItem measurements by their Id.
private readonly Dictionary<ICalendarItem, CalendarItemMeasurement> _measurements = new Dictionary<ICalendarItem, CalendarItemMeasurement>();
public static readonly DependencyProperty EventItemMarginProperty = DependencyProperty.Register(nameof(EventItemMargin), typeof(Thickness), typeof(WinoCalendarPanel), new PropertyMetadata(new Thickness(0, 0, 0, 0)));
public static readonly DependencyProperty HourHeightProperty = DependencyProperty.Register(nameof(HourHeight), typeof(double), typeof(WinoCalendarPanel), new PropertyMetadata(0d));
public static readonly DependencyProperty PeriodProperty = DependencyProperty.Register(nameof(Period), typeof(ITimePeriod), typeof(WinoCalendarPanel), new PropertyMetadata(null));
public ITimePeriod Period
{ {
private const double LastItemRightExtraMargin = 12d; get { return (ITimePeriod)GetValue(PeriodProperty); }
set { SetValue(PeriodProperty, value); }
}
// Store each ICalendarItem measurements by their Id. public double HourHeight
private readonly Dictionary<ICalendarItem, CalendarItemMeasurement> _measurements = new Dictionary<ICalendarItem, CalendarItemMeasurement>(); {
get { return (double)GetValue(HourHeightProperty); }
set { SetValue(HourHeightProperty, value); }
}
public static readonly DependencyProperty EventItemMarginProperty = DependencyProperty.Register(nameof(EventItemMargin), typeof(Thickness), typeof(WinoCalendarPanel), new PropertyMetadata(new Thickness(0, 0, 0, 0))); public Thickness EventItemMargin
public static readonly DependencyProperty HourHeightProperty = DependencyProperty.Register(nameof(HourHeight), typeof(double), typeof(WinoCalendarPanel), new PropertyMetadata(0d)); {
public static readonly DependencyProperty PeriodProperty = DependencyProperty.Register(nameof(Period), typeof(ITimePeriod), typeof(WinoCalendarPanel), new PropertyMetadata(null)); get { return (Thickness)GetValue(EventItemMarginProperty); }
set { SetValue(EventItemMarginProperty, value); }
}
public ITimePeriod Period private void ResetMeasurements() => _measurements.Clear();
private double GetChildTopMargin(ICalendarItem calendarItemViewModel, double availableHeight)
{
var childStart = calendarItemViewModel.StartDate;
if (childStart <= Period.Start)
{ {
get { return (ITimePeriod)GetValue(PeriodProperty); } // Event started before or exactly at the periods tart. This might be a multi-day event.
set { SetValue(PeriodProperty, value); } // We can simply consider event must not have a top margin.
return 0d;
} }
public double HourHeight double minutesFromStart = (childStart - Period.Start).TotalMinutes;
return (minutesFromStart / 1440) * availableHeight;
}
private double GetChildWidth(CalendarItemMeasurement calendarItemMeasurement, double availableWidth)
{
return (calendarItemMeasurement.Right - calendarItemMeasurement.Left) * availableWidth;
}
private double GetChildLeftMargin(CalendarItemMeasurement calendarItemMeasurement, double availableWidth)
=> availableWidth * calendarItemMeasurement.Left;
private double GetChildHeight(ICalendarItem child)
{
// All day events are not measured.
if (child.IsAllDayEvent) return 0;
double childDurationInMinutes = 0d;
double availableHeight = HourHeight * 24;
var periodRelation = child.Period.GetRelation(Period);
// Debug.WriteLine($"Render relation of {child.Title} ({child.Period.Start} - {child.Period.End}) is {periodRelation} with {Period.Start.Day}");
if (!child.IsMultiDayEvent)
{ {
get { return (double)GetValue(HourHeightProperty); } childDurationInMinutes = child.Period.Duration.TotalMinutes;
set { SetValue(HourHeightProperty, value); } }
else
{
// Multi-day event.
// Check how many of the event falls into the current period.
childDurationInMinutes = (child.Period.End - Period.Start).TotalMinutes;
} }
public Thickness EventItemMargin return (childDurationInMinutes / 1440) * availableHeight;
}
protected override Size MeasureOverride(Size availableSize)
{
ResetMeasurements();
return base.MeasureOverride(availableSize);
}
protected override Size ArrangeOverride(Size finalSize)
{
if (Period == null || HourHeight == 0d) return finalSize;
// Measure/arrange each child height and width.
// This is a vertical calendar. Therefore the height of each child is the duration of the event.
// Children weights for left and right will be saved if they don't exist.
// This is important because we don't want to measure the weights again.
// They don't change until new event is added or removed.
// Width of the each child may depend on the rectangle packing algorithm.
// Children are first categorized into columns. Then each column is shifted to the left until
// no overlap occurs. The width of each child is calculated based on the number of columns it spans.
double availableHeight = finalSize.Height;
double availableWidth = finalSize.Width;
var calendarControls = Children.Cast<ContentPresenter>();
if (!calendarControls.Any()) return base.ArrangeOverride(finalSize);
var events = calendarControls.Select(a => a.Content as CalendarItemViewModel);
LayoutEvents(events);
foreach (var control in calendarControls)
{ {
get { return (Thickness)GetValue(EventItemMarginProperty); } // We can't arrange this child.
set { SetValue(EventItemMarginProperty, value); } if (!(control.Content is ICalendarItem child)) continue;
}
private void ResetMeasurements() => _measurements.Clear(); bool isHorizontallyLastItem = false;
private double GetChildTopMargin(ICalendarItem calendarItemViewModel, double availableHeight) double childWidth = 0,
{ childHeight = Math.Max(0, GetChildHeight(child)),
var childStart = calendarItemViewModel.StartDate; childTop = Math.Max(0, GetChildTopMargin(child, availableHeight)),
childLeft = 0;
if (childStart <= Period.Start) // No need to measure anything here.
{ if (childHeight == 0) continue;
// Event started before or exactly at the periods tart. This might be a multi-day event.
// We can simply consider event must not have a top margin.
return 0d; if (!_measurements.ContainsKey(child))
}
double minutesFromStart = (childStart - Period.Start).TotalMinutes;
return (minutesFromStart / 1440) * availableHeight;
}
private double GetChildWidth(CalendarItemMeasurement calendarItemMeasurement, double availableWidth)
{
return (calendarItemMeasurement.Right - calendarItemMeasurement.Left) * availableWidth;
}
private double GetChildLeftMargin(CalendarItemMeasurement calendarItemMeasurement, double availableWidth)
=> availableWidth * calendarItemMeasurement.Left;
private double GetChildHeight(ICalendarItem child)
{
// All day events are not measured.
if (child.IsAllDayEvent) return 0;
double childDurationInMinutes = 0d;
double availableHeight = HourHeight * 24;
var periodRelation = child.Period.GetRelation(Period);
// Debug.WriteLine($"Render relation of {child.Title} ({child.Period.Start} - {child.Period.End}) is {periodRelation} with {Period.Start.Day}");
if (!child.IsMultiDayEvent)
{
childDurationInMinutes = child.Period.Duration.TotalMinutes;
}
else
{ {
// Multi-day event. // Multi-day event.
// Check how many of the event falls into the current period.
childDurationInMinutes = (child.Period.End - Period.Start).TotalMinutes;
}
return (childDurationInMinutes / 1440) * availableHeight; childLeft = 0;
} childWidth = availableWidth;
protected override Size MeasureOverride(Size availableSize)
{
ResetMeasurements();
return base.MeasureOverride(availableSize);
}
protected override Size ArrangeOverride(Size finalSize)
{
if (Period == null || HourHeight == 0d) return finalSize;
// Measure/arrange each child height and width.
// This is a vertical calendar. Therefore the height of each child is the duration of the event.
// Children weights for left and right will be saved if they don't exist.
// This is important because we don't want to measure the weights again.
// They don't change until new event is added or removed.
// Width of the each child may depend on the rectangle packing algorithm.
// Children are first categorized into columns. Then each column is shifted to the left until
// no overlap occurs. The width of each child is calculated based on the number of columns it spans.
double availableHeight = finalSize.Height;
double availableWidth = finalSize.Width;
var calendarControls = Children.Cast<ContentPresenter>();
if (!calendarControls.Any()) return base.ArrangeOverride(finalSize);
var events = calendarControls.Select(a => a.Content as CalendarItemViewModel);
LayoutEvents(events);
foreach (var control in calendarControls)
{
// We can't arrange this child.
if (!(control.Content is ICalendarItem child)) continue;
bool isHorizontallyLastItem = false;
double childWidth = 0,
childHeight = Math.Max(0, GetChildHeight(child)),
childTop = Math.Max(0, GetChildTopMargin(child, availableHeight)),
childLeft = 0;
// No need to measure anything here.
if (childHeight == 0) continue;
if (!_measurements.ContainsKey(child))
{
// Multi-day event.
childLeft = 0;
childWidth = availableWidth;
}
else
{
var childMeasurement = _measurements[child];
childWidth = Math.Max(0, GetChildWidth(childMeasurement, finalSize.Width));
childLeft = Math.Max(0, GetChildLeftMargin(childMeasurement, availableWidth));
isHorizontallyLastItem = childMeasurement.Right == 1;
}
// Add additional right margin to items that falls on the right edge of the panel.
double extraRightMargin = 0;
// Multi-day events don't have any margin and their hit test is disabled.
if (!child.IsMultiDayEvent)
{
// Max of 5% of the width or 20px max.
extraRightMargin = isHorizontallyLastItem ? Math.Max(LastItemRightExtraMargin, finalSize.Width * 5 / 100) : 0;
}
if (childWidth < 0) childWidth = 1;
// Regular events must have 2px margin
if (!child.IsMultiDayEvent && !child.IsAllDayEvent)
{
childLeft += 2;
childTop += 2;
childHeight -= 2;
childWidth -= 2;
}
var arrangementRect = new Rect(childLeft + EventItemMargin.Left, childTop + EventItemMargin.Top, Math.Max(childWidth - extraRightMargin, 1), childHeight);
// Make sure measured size will fit in the arranged box.
var measureSize = arrangementRect.ToSize();
control.Measure(measureSize);
control.Arrange(arrangementRect);
//Debug.WriteLine($"{child.Title}, Measured: {measureSize}, Arranged: {arrangementRect}");
}
return finalSize;
}
#region ColumSpanning and Packing Algorithm
private void AddOrUpdateMeasurement(ICalendarItem calendarItem, CalendarItemMeasurement measurement)
{
if (_measurements.ContainsKey(calendarItem))
{
_measurements[calendarItem] = measurement;
} }
else else
{ {
_measurements.Add(calendarItem, measurement); var childMeasurement = _measurements[child];
childWidth = Math.Max(0, GetChildWidth(childMeasurement, finalSize.Width));
childLeft = Math.Max(0, GetChildLeftMargin(childMeasurement, availableWidth));
isHorizontallyLastItem = childMeasurement.Right == 1;
} }
// Add additional right margin to items that falls on the right edge of the panel.
double extraRightMargin = 0;
// Multi-day events don't have any margin and their hit test is disabled.
if (!child.IsMultiDayEvent)
{
// Max of 5% of the width or 20px max.
extraRightMargin = isHorizontallyLastItem ? Math.Max(LastItemRightExtraMargin, finalSize.Width * 5 / 100) : 0;
}
if (childWidth < 0) childWidth = 1;
// Regular events must have 2px margin
if (!child.IsMultiDayEvent && !child.IsAllDayEvent)
{
childLeft += 2;
childTop += 2;
childHeight -= 2;
childWidth -= 2;
}
var arrangementRect = new Rect(childLeft + EventItemMargin.Left, childTop + EventItemMargin.Top, Math.Max(childWidth - extraRightMargin, 1), childHeight);
// Make sure measured size will fit in the arranged box.
var measureSize = arrangementRect.ToSize();
control.Measure(measureSize);
control.Arrange(arrangementRect);
//Debug.WriteLine($"{child.Title}, Measured: {measureSize}, Arranged: {arrangementRect}");
} }
// Pick the left and right positions of each event, such that there are no overlap.
private void LayoutEvents(IEnumerable<ICalendarItem> events) return finalSize;
}
#region ColumSpanning and Packing Algorithm
private void AddOrUpdateMeasurement(ICalendarItem calendarItem, CalendarItemMeasurement measurement)
{
if (_measurements.ContainsKey(calendarItem))
{ {
var columns = new List<List<ICalendarItem>>(); _measurements[calendarItem] = measurement;
DateTime? lastEventEnding = null; }
else
{
_measurements.Add(calendarItem, measurement);
}
}
foreach (var ev in events.OrderBy(ev => ev.StartDate).ThenBy(ev => ev.EndDate)) // Pick the left and right positions of each event, such that there are no overlap.
{ private void LayoutEvents(IEnumerable<ICalendarItem> events)
// Multi-day events are not measured. {
if (ev.IsMultiDayEvent) continue; var columns = new List<List<ICalendarItem>>();
DateTime? lastEventEnding = null;
if (ev.Period.Start >= lastEventEnding) foreach (var ev in events.OrderBy(ev => ev.StartDate).ThenBy(ev => ev.EndDate))
{ {
PackEvents(columns); // Multi-day events are not measured.
columns.Clear(); if (ev.IsMultiDayEvent) continue;
lastEventEnding = null;
}
bool placed = false; if (ev.Period.Start >= lastEventEnding)
foreach (var col in columns)
{
if (!col.Last().Period.OverlapsWith(ev.Period))
{
col.Add(ev);
placed = true;
break;
}
}
if (!placed)
{
columns.Add(new List<ICalendarItem> { ev });
}
if (lastEventEnding == null || ev.Period.End > lastEventEnding.Value)
{
lastEventEnding = ev.Period.End;
}
}
if (columns.Count > 0)
{ {
PackEvents(columns); PackEvents(columns);
columns.Clear();
lastEventEnding = null;
} }
}
// Set the left and right positions for each event in the connected group. bool placed = false;
private void PackEvents(List<List<ICalendarItem>> columns)
{
float numColumns = columns.Count;
int iColumn = 0;
foreach (var col in columns) foreach (var col in columns)
{ {
foreach (var ev in col) if (!col.Last().Period.OverlapsWith(ev.Period))
{ {
int colSpan = ExpandEvent(ev, iColumn, columns); col.Add(ev);
placed = true;
var leftWeight = iColumn / numColumns; break;
var rightWeight = (iColumn + colSpan) / numColumns;
AddOrUpdateMeasurement(ev, new CalendarItemMeasurement(leftWeight, rightWeight));
} }
iColumn++;
} }
} if (!placed)
// Checks how many columns the event can expand into, without colliding with other events.
private int ExpandEvent(ICalendarItem ev, int iColumn, List<List<ICalendarItem>> columns)
{
int colSpan = 1;
foreach (var col in columns.Skip(iColumn + 1))
{ {
foreach (var ev1 in col) columns.Add(new List<ICalendarItem> { ev });
{ }
if (ev1.Period.OverlapsWith(ev.Period)) return colSpan; if (lastEventEnding == null || ev.Period.End > lastEventEnding.Value)
} {
lastEventEnding = ev.Period.End;
}
}
if (columns.Count > 0)
{
PackEvents(columns);
}
}
colSpan++; // Set the left and right positions for each event in the connected group.
private void PackEvents(List<List<ICalendarItem>> columns)
{
float numColumns = columns.Count;
int iColumn = 0;
foreach (var col in columns)
{
foreach (var ev in col)
{
int colSpan = ExpandEvent(ev, iColumn, columns);
var leftWeight = iColumn / numColumns;
var rightWeight = (iColumn + colSpan) / numColumns;
AddOrUpdateMeasurement(ev, new CalendarItemMeasurement(leftWeight, rightWeight));
} }
return colSpan; iColumn++;
}
}
// Checks how many columns the event can expand into, without colliding with other events.
private int ExpandEvent(ICalendarItem ev, int iColumn, List<List<ICalendarItem>> columns)
{
int colSpan = 1;
foreach (var col in columns.Skip(iColumn + 1))
{
foreach (var ev1 in col)
{
if (ev1.Period.OverlapsWith(ev.Period)) return colSpan;
}
colSpan++;
} }
#endregion return colSpan;
} }
#endregion
} }

View File

@@ -4,89 +4,88 @@ using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Wino.Core.Domain.Enums; using Wino.Core.Domain.Enums;
namespace Wino.Calendar.Controls namespace Wino.Calendar.Controls;
public partial class WinoCalendarTypeSelectorControl : Control
{ {
public class WinoCalendarTypeSelectorControl : Control private const string PART_TodayButton = nameof(PART_TodayButton);
private const string PART_DayToggle = nameof(PART_DayToggle);
private const string PART_WeekToggle = nameof(PART_WeekToggle);
private const string PART_MonthToggle = nameof(PART_MonthToggle);
private const string PART_YearToggle = nameof(PART_YearToggle);
public static readonly DependencyProperty SelectedTypeProperty = DependencyProperty.Register(nameof(SelectedType), typeof(CalendarDisplayType), typeof(WinoCalendarTypeSelectorControl), new PropertyMetadata(CalendarDisplayType.Week));
public static readonly DependencyProperty DisplayDayCountProperty = DependencyProperty.Register(nameof(DisplayDayCount), typeof(int), typeof(WinoCalendarTypeSelectorControl), new PropertyMetadata(0));
public static readonly DependencyProperty TodayClickedCommandProperty = DependencyProperty.Register(nameof(TodayClickedCommand), typeof(ICommand), typeof(WinoCalendarTypeSelectorControl), new PropertyMetadata(null));
public ICommand TodayClickedCommand
{ {
private const string PART_TodayButton = nameof(PART_TodayButton); get { return (ICommand)GetValue(TodayClickedCommandProperty); }
private const string PART_DayToggle = nameof(PART_DayToggle); set { SetValue(TodayClickedCommandProperty, value); }
private const string PART_WeekToggle = nameof(PART_WeekToggle); }
private const string PART_MonthToggle = nameof(PART_MonthToggle);
private const string PART_YearToggle = nameof(PART_YearToggle);
public static readonly DependencyProperty SelectedTypeProperty = DependencyProperty.Register(nameof(SelectedType), typeof(CalendarDisplayType), typeof(WinoCalendarTypeSelectorControl), new PropertyMetadata(CalendarDisplayType.Week)); public CalendarDisplayType SelectedType
public static readonly DependencyProperty DisplayDayCountProperty = DependencyProperty.Register(nameof(DisplayDayCount), typeof(int), typeof(WinoCalendarTypeSelectorControl), new PropertyMetadata(0)); {
public static readonly DependencyProperty TodayClickedCommandProperty = DependencyProperty.Register(nameof(TodayClickedCommand), typeof(ICommand), typeof(WinoCalendarTypeSelectorControl), new PropertyMetadata(null)); get { return (CalendarDisplayType)GetValue(SelectedTypeProperty); }
set { SetValue(SelectedTypeProperty, value); }
}
public ICommand TodayClickedCommand public int DisplayDayCount
{ {
get { return (ICommand)GetValue(TodayClickedCommandProperty); } get { return (int)GetValue(DisplayDayCountProperty); }
set { SetValue(TodayClickedCommandProperty, value); } set { SetValue(DisplayDayCountProperty, value); }
} }
public CalendarDisplayType SelectedType private AppBarButton _todayButton;
{ private AppBarToggleButton _dayToggle;
get { return (CalendarDisplayType)GetValue(SelectedTypeProperty); } private AppBarToggleButton _weekToggle;
set { SetValue(SelectedTypeProperty, value); } private AppBarToggleButton _monthToggle;
} private AppBarToggleButton _yearToggle;
public int DisplayDayCount public WinoCalendarTypeSelectorControl()
{ {
get { return (int)GetValue(DisplayDayCountProperty); } DefaultStyleKey = typeof(WinoCalendarTypeSelectorControl);
set { SetValue(DisplayDayCountProperty, value); } }
}
private AppBarButton _todayButton; protected override void OnApplyTemplate()
private AppBarToggleButton _dayToggle; {
private AppBarToggleButton _weekToggle; base.OnApplyTemplate();
private AppBarToggleButton _monthToggle;
private AppBarToggleButton _yearToggle;
public WinoCalendarTypeSelectorControl() _todayButton = GetTemplateChild(PART_TodayButton) as AppBarButton;
{ _dayToggle = GetTemplateChild(PART_DayToggle) as AppBarToggleButton;
DefaultStyleKey = typeof(WinoCalendarTypeSelectorControl); _weekToggle = GetTemplateChild(PART_WeekToggle) as AppBarToggleButton;
} _monthToggle = GetTemplateChild(PART_MonthToggle) as AppBarToggleButton;
_yearToggle = GetTemplateChild(PART_YearToggle) as AppBarToggleButton;
protected override void OnApplyTemplate() Guard.IsNotNull(_todayButton, nameof(_todayButton));
{ Guard.IsNotNull(_dayToggle, nameof(_dayToggle));
base.OnApplyTemplate(); Guard.IsNotNull(_weekToggle, nameof(_weekToggle));
Guard.IsNotNull(_monthToggle, nameof(_monthToggle));
Guard.IsNotNull(_yearToggle, nameof(_yearToggle));
_todayButton = GetTemplateChild(PART_TodayButton) as AppBarButton; _todayButton.Click += TodayClicked;
_dayToggle = GetTemplateChild(PART_DayToggle) as AppBarToggleButton;
_weekToggle = GetTemplateChild(PART_WeekToggle) as AppBarToggleButton;
_monthToggle = GetTemplateChild(PART_MonthToggle) as AppBarToggleButton;
_yearToggle = GetTemplateChild(PART_YearToggle) as AppBarToggleButton;
Guard.IsNotNull(_todayButton, nameof(_todayButton)); _dayToggle.Click += (s, e) => { SetSelectedType(CalendarDisplayType.Day); };
Guard.IsNotNull(_dayToggle, nameof(_dayToggle)); _weekToggle.Click += (s, e) => { SetSelectedType(CalendarDisplayType.Week); };
Guard.IsNotNull(_weekToggle, nameof(_weekToggle)); _monthToggle.Click += (s, e) => { SetSelectedType(CalendarDisplayType.Month); };
Guard.IsNotNull(_monthToggle, nameof(_monthToggle)); _yearToggle.Click += (s, e) => { SetSelectedType(CalendarDisplayType.Year); };
Guard.IsNotNull(_yearToggle, nameof(_yearToggle));
_todayButton.Click += TodayClicked; UpdateToggleButtonStates();
}
_dayToggle.Click += (s, e) => { SetSelectedType(CalendarDisplayType.Day); }; private void TodayClicked(object sender, RoutedEventArgs e) => TodayClickedCommand?.Execute(null);
_weekToggle.Click += (s, e) => { SetSelectedType(CalendarDisplayType.Week); };
_monthToggle.Click += (s, e) => { SetSelectedType(CalendarDisplayType.Month); };
_yearToggle.Click += (s, e) => { SetSelectedType(CalendarDisplayType.Year); };
UpdateToggleButtonStates(); private void SetSelectedType(CalendarDisplayType type)
} {
SelectedType = type;
UpdateToggleButtonStates();
}
private void TodayClicked(object sender, RoutedEventArgs e) => TodayClickedCommand?.Execute(null); private void UpdateToggleButtonStates()
{
private void SetSelectedType(CalendarDisplayType type) _dayToggle.IsChecked = SelectedType == CalendarDisplayType.Day;
{ _weekToggle.IsChecked = SelectedType == CalendarDisplayType.Week;
SelectedType = type; _monthToggle.IsChecked = SelectedType == CalendarDisplayType.Month;
UpdateToggleButtonStates(); _yearToggle.IsChecked = SelectedType == CalendarDisplayType.Year;
}
private void UpdateToggleButtonStates()
{
_dayToggle.IsChecked = SelectedType == CalendarDisplayType.Day;
_weekToggle.IsChecked = SelectedType == CalendarDisplayType.Week;
_monthToggle.IsChecked = SelectedType == CalendarDisplayType.Month;
_yearToggle.IsChecked = SelectedType == CalendarDisplayType.Year;
}
} }
} }

View File

@@ -8,140 +8,139 @@ using Windows.UI.Xaml.Media;
using Wino.Core.Domain.Models.Calendar; using Wino.Core.Domain.Models.Calendar;
using Wino.Helpers; using Wino.Helpers;
namespace Wino.Calendar.Controls namespace Wino.Calendar.Controls;
public partial class WinoCalendarView : Control
{ {
public class WinoCalendarView : Control private const string PART_DayViewItemBorder = nameof(PART_DayViewItemBorder);
private const string PART_CalendarView = nameof(PART_CalendarView);
public static readonly DependencyProperty HighlightedDateRangeProperty = DependencyProperty.Register(nameof(HighlightedDateRange), typeof(DateRange), typeof(WinoCalendarView), new PropertyMetadata(null, new PropertyChangedCallback(OnHighlightedDateRangeChanged)));
public static readonly DependencyProperty VisibleDateBackgroundProperty = DependencyProperty.Register(nameof(VisibleDateBackground), typeof(Brush), typeof(WinoCalendarView), new PropertyMetadata(null, new PropertyChangedCallback(OnPropertiesChanged)));
public static readonly DependencyProperty DateClickedCommandProperty = DependencyProperty.Register(nameof(DateClickedCommand), typeof(ICommand), typeof(WinoCalendarView), new PropertyMetadata(null));
public static readonly DependencyProperty TodayBackgroundColorProperty = DependencyProperty.Register(nameof(TodayBackgroundColor), typeof(Color), typeof(WinoCalendarView), new PropertyMetadata(null));
public Color TodayBackgroundColor
{ {
private const string PART_DayViewItemBorder = nameof(PART_DayViewItemBorder); get { return (Color)GetValue(TodayBackgroundColorProperty); }
private const string PART_CalendarView = nameof(PART_CalendarView); set { SetValue(TodayBackgroundColorProperty, value); }
}
public static readonly DependencyProperty HighlightedDateRangeProperty = DependencyProperty.Register(nameof(HighlightedDateRange), typeof(DateRange), typeof(WinoCalendarView), new PropertyMetadata(null, new PropertyChangedCallback(OnHighlightedDateRangeChanged))); /// <summary>
public static readonly DependencyProperty VisibleDateBackgroundProperty = DependencyProperty.Register(nameof(VisibleDateBackground), typeof(Brush), typeof(WinoCalendarView), new PropertyMetadata(null, new PropertyChangedCallback(OnPropertiesChanged))); /// Gets or sets the command to execute when a date is picked.
public static readonly DependencyProperty DateClickedCommandProperty = DependencyProperty.Register(nameof(DateClickedCommand), typeof(ICommand), typeof(WinoCalendarView), new PropertyMetadata(null)); /// Unused.
public static readonly DependencyProperty TodayBackgroundColorProperty = DependencyProperty.Register(nameof(TodayBackgroundColor), typeof(Color), typeof(WinoCalendarView), new PropertyMetadata(null)); /// </summary>
public ICommand DateClickedCommand
{
get { return (ICommand)GetValue(DateClickedCommandProperty); }
set { SetValue(DateClickedCommandProperty, value); }
}
public Color TodayBackgroundColor /// <summary>
/// Gets or sets the highlighted range of dates.
/// </summary>
public DateRange HighlightedDateRange
{
get { return (DateRange)GetValue(HighlightedDateRangeProperty); }
set { SetValue(HighlightedDateRangeProperty, value); }
}
public Brush VisibleDateBackground
{
get { return (Brush)GetValue(VisibleDateBackgroundProperty); }
set { SetValue(VisibleDateBackgroundProperty, value); }
}
private CalendarView CalendarView;
public WinoCalendarView()
{
DefaultStyleKey = typeof(WinoCalendarView);
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
CalendarView = GetTemplateChild(PART_CalendarView) as CalendarView;
Guard.IsNotNull(CalendarView, nameof(CalendarView));
CalendarView.SelectedDatesChanged -= InternalCalendarViewSelectionChanged;
CalendarView.SelectedDatesChanged += InternalCalendarViewSelectionChanged;
// TODO: Should come from settings.
CalendarView.FirstDayOfWeek = Windows.Globalization.DayOfWeek.Monday;
// Everytime display mode changes, update the visible date range backgrounds.
// If users go back from year -> month -> day, we need to update the visible date range backgrounds.
CalendarView.RegisterPropertyChangedCallback(CalendarView.DisplayModeProperty, (s, e) => UpdateVisibleDateRangeBackgrounds());
}
private void InternalCalendarViewSelectionChanged(CalendarView sender, CalendarViewSelectedDatesChangedEventArgs args)
{
if (args.AddedDates?.Count > 0)
{ {
get { return (Color)GetValue(TodayBackgroundColorProperty); } var clickedDate = args.AddedDates[0].Date;
set { SetValue(TodayBackgroundColorProperty, value); } SetInnerDisplayDate(clickedDate);
var clickArgs = new CalendarViewDayClickedEventArgs(clickedDate);
DateClickedCommand?.Execute(clickArgs);
} }
/// <summary> // Reset selection, we don't show selected dates but react to them.
/// Gets or sets the command to execute when a date is picked. CalendarView.SelectedDates.Clear();
/// Unused. }
/// </summary>
public ICommand DateClickedCommand private static void OnPropertiesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is WinoCalendarView control)
{ {
get { return (ICommand)GetValue(DateClickedCommandProperty); } control.UpdateVisibleDateRangeBackgrounds();
set { SetValue(DateClickedCommandProperty, value); }
} }
}
/// <summary> private void SetInnerDisplayDate(DateTime dateTime) => CalendarView?.SetDisplayDate(dateTime);
/// Gets or sets the highlighted range of dates.
/// </summary> // Changing selected dates will trigger the selection changed event.
public DateRange HighlightedDateRange // It will behave like user clicked the date.
public void GoToDay(DateTime dateTime) => CalendarView.SelectedDates.Add(dateTime);
private static void OnHighlightedDateRangeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is WinoCalendarView control)
{ {
get { return (DateRange)GetValue(HighlightedDateRangeProperty); } control.SetInnerDisplayDate(control.HighlightedDateRange.StartDate);
set { SetValue(HighlightedDateRangeProperty, value); } control.UpdateVisibleDateRangeBackgrounds();
} }
}
public Brush VisibleDateBackground public void UpdateVisibleDateRangeBackgrounds()
{
if (HighlightedDateRange == null || VisibleDateBackground == null || TodayBackgroundColor == null || CalendarView == null) return;
var markDateCalendarDayItems = WinoVisualTreeHelper.FindDescendants<CalendarViewDayItem>(CalendarView);
foreach (var calendarDayItem in markDateCalendarDayItems)
{ {
get { return (Brush)GetValue(VisibleDateBackgroundProperty); } var border = WinoVisualTreeHelper.GetChildObject<Border>(calendarDayItem, PART_DayViewItemBorder);
set { SetValue(VisibleDateBackgroundProperty, value); }
}
if (border == null) return;
if (calendarDayItem.Date.Date == DateTime.Today.Date)
private CalendarView CalendarView;
public WinoCalendarView()
{
DefaultStyleKey = typeof(WinoCalendarView);
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
CalendarView = GetTemplateChild(PART_CalendarView) as CalendarView;
Guard.IsNotNull(CalendarView, nameof(CalendarView));
CalendarView.SelectedDatesChanged -= InternalCalendarViewSelectionChanged;
CalendarView.SelectedDatesChanged += InternalCalendarViewSelectionChanged;
// TODO: Should come from settings.
CalendarView.FirstDayOfWeek = Windows.Globalization.DayOfWeek.Monday;
// Everytime display mode changes, update the visible date range backgrounds.
// If users go back from year -> month -> day, we need to update the visible date range backgrounds.
CalendarView.RegisterPropertyChangedCallback(CalendarView.DisplayModeProperty, (s, e) => UpdateVisibleDateRangeBackgrounds());
}
private void InternalCalendarViewSelectionChanged(CalendarView sender, CalendarViewSelectedDatesChangedEventArgs args)
{
if (args.AddedDates?.Count > 0)
{ {
var clickedDate = args.AddedDates[0].Date; border.Background = new SolidColorBrush(TodayBackgroundColor);
SetInnerDisplayDate(clickedDate);
var clickArgs = new CalendarViewDayClickedEventArgs(clickedDate);
DateClickedCommand?.Execute(clickArgs);
} }
else if (calendarDayItem.Date.Date >= HighlightedDateRange.StartDate.Date && calendarDayItem.Date.Date < HighlightedDateRange.EndDate.Date)
// Reset selection, we don't show selected dates but react to them.
CalendarView.SelectedDates.Clear();
}
private static void OnPropertiesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is WinoCalendarView control)
{ {
control.UpdateVisibleDateRangeBackgrounds(); border.Background = VisibleDateBackground;
} }
} else
private void SetInnerDisplayDate(DateTime dateTime) => CalendarView?.SetDisplayDate(dateTime);
// Changing selected dates will trigger the selection changed event.
// It will behave like user clicked the date.
public void GoToDay(DateTime dateTime) => CalendarView.SelectedDates.Add(dateTime);
private static void OnHighlightedDateRangeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is WinoCalendarView control)
{ {
control.SetInnerDisplayDate(control.HighlightedDateRange.StartDate); border.Background = null;
control.UpdateVisibleDateRangeBackgrounds();
}
}
public void UpdateVisibleDateRangeBackgrounds()
{
if (HighlightedDateRange == null || VisibleDateBackground == null || TodayBackgroundColor == null || CalendarView == null) return;
var markDateCalendarDayItems = WinoVisualTreeHelper.FindDescendants<CalendarViewDayItem>(CalendarView);
foreach (var calendarDayItem in markDateCalendarDayItems)
{
var border = WinoVisualTreeHelper.GetChildObject<Border>(calendarDayItem, PART_DayViewItemBorder);
if (border == null) return;
if (calendarDayItem.Date.Date == DateTime.Today.Date)
{
border.Background = new SolidColorBrush(TodayBackgroundColor);
}
else if (calendarDayItem.Date.Date >= HighlightedDateRange.StartDate.Date && calendarDayItem.Date.Date < HighlightedDateRange.EndDate.Date)
{
border.Background = VisibleDateBackground;
}
else
{
border.Background = null;
}
} }
} }
} }

View File

@@ -10,269 +10,268 @@ using Windows.UI.Xaml.Media;
using Wino.Calendar.Args; using Wino.Calendar.Args;
using Wino.Core.Domain.Models.Calendar; using Wino.Core.Domain.Models.Calendar;
namespace Wino.Calendar.Controls namespace Wino.Calendar.Controls;
public partial class WinoDayTimelineCanvas : Control, IDisposable
{ {
public class WinoDayTimelineCanvas : Control, IDisposable public event EventHandler<TimelineCellSelectedArgs> TimelineCellSelected;
public event EventHandler<TimelineCellUnselectedArgs> TimelineCellUnselected;
private const string PART_InternalCanvas = nameof(PART_InternalCanvas);
private CanvasControl Canvas;
public static readonly DependencyProperty RenderOptionsProperty = DependencyProperty.Register(nameof(RenderOptions), typeof(CalendarRenderOptions), typeof(WinoDayTimelineCanvas), new PropertyMetadata(null, new PropertyChangedCallback(OnRenderingPropertiesChanged)));
public static readonly DependencyProperty SeperatorColorProperty = DependencyProperty.Register(nameof(SeperatorColor), typeof(SolidColorBrush), typeof(WinoDayTimelineCanvas), new PropertyMetadata(null, new PropertyChangedCallback(OnRenderingPropertiesChanged)));
public static readonly DependencyProperty HalfHourSeperatorColorProperty = DependencyProperty.Register(nameof(HalfHourSeperatorColor), typeof(SolidColorBrush), typeof(WinoDayTimelineCanvas), new PropertyMetadata(null, new PropertyChangedCallback(OnRenderingPropertiesChanged)));
public static readonly DependencyProperty SelectedCellBackgroundBrushProperty = DependencyProperty.Register(nameof(SelectedCellBackgroundBrush), typeof(SolidColorBrush), typeof(WinoDayTimelineCanvas), new PropertyMetadata(null, new PropertyChangedCallback(OnRenderingPropertiesChanged)));
public static readonly DependencyProperty WorkingHourCellBackgroundColorProperty = DependencyProperty.Register(nameof(WorkingHourCellBackgroundColor), typeof(SolidColorBrush), typeof(WinoDayTimelineCanvas), new PropertyMetadata(null, new PropertyChangedCallback(OnRenderingPropertiesChanged)));
public static readonly DependencyProperty SelectedDateTimeProperty = DependencyProperty.Register(nameof(SelectedDateTime), typeof(DateTime?), typeof(WinoDayTimelineCanvas), new PropertyMetadata(null, new PropertyChangedCallback(OnSelectedDateTimeChanged)));
public static readonly DependencyProperty PositionerUIElementProperty = DependencyProperty.Register(nameof(PositionerUIElement), typeof(UIElement), typeof(WinoDayTimelineCanvas), new PropertyMetadata(null));
public UIElement PositionerUIElement
{ {
public event EventHandler<TimelineCellSelectedArgs> TimelineCellSelected; get { return (UIElement)GetValue(PositionerUIElementProperty); }
public event EventHandler<TimelineCellUnselectedArgs> TimelineCellUnselected; set { SetValue(PositionerUIElementProperty, value); }
}
private const string PART_InternalCanvas = nameof(PART_InternalCanvas); public CalendarRenderOptions RenderOptions
private CanvasControl Canvas; {
get { return (CalendarRenderOptions)GetValue(RenderOptionsProperty); }
set { SetValue(RenderOptionsProperty, value); }
}
public static readonly DependencyProperty RenderOptionsProperty = DependencyProperty.Register(nameof(RenderOptions), typeof(CalendarRenderOptions), typeof(WinoDayTimelineCanvas), new PropertyMetadata(null, new PropertyChangedCallback(OnRenderingPropertiesChanged))); public SolidColorBrush HalfHourSeperatorColor
public static readonly DependencyProperty SeperatorColorProperty = DependencyProperty.Register(nameof(SeperatorColor), typeof(SolidColorBrush), typeof(WinoDayTimelineCanvas), new PropertyMetadata(null, new PropertyChangedCallback(OnRenderingPropertiesChanged))); {
public static readonly DependencyProperty HalfHourSeperatorColorProperty = DependencyProperty.Register(nameof(HalfHourSeperatorColor), typeof(SolidColorBrush), typeof(WinoDayTimelineCanvas), new PropertyMetadata(null, new PropertyChangedCallback(OnRenderingPropertiesChanged))); get { return (SolidColorBrush)GetValue(HalfHourSeperatorColorProperty); }
public static readonly DependencyProperty SelectedCellBackgroundBrushProperty = DependencyProperty.Register(nameof(SelectedCellBackgroundBrush), typeof(SolidColorBrush), typeof(WinoDayTimelineCanvas), new PropertyMetadata(null, new PropertyChangedCallback(OnRenderingPropertiesChanged))); set { SetValue(HalfHourSeperatorColorProperty, value); }
public static readonly DependencyProperty WorkingHourCellBackgroundColorProperty = DependencyProperty.Register(nameof(WorkingHourCellBackgroundColor), typeof(SolidColorBrush), typeof(WinoDayTimelineCanvas), new PropertyMetadata(null, new PropertyChangedCallback(OnRenderingPropertiesChanged))); }
public static readonly DependencyProperty SelectedDateTimeProperty = DependencyProperty.Register(nameof(SelectedDateTime), typeof(DateTime?), typeof(WinoDayTimelineCanvas), new PropertyMetadata(null, new PropertyChangedCallback(OnSelectedDateTimeChanged)));
public static readonly DependencyProperty PositionerUIElementProperty = DependencyProperty.Register(nameof(PositionerUIElement), typeof(UIElement), typeof(WinoDayTimelineCanvas), new PropertyMetadata(null));
public UIElement PositionerUIElement public SolidColorBrush SeperatorColor
{
get { return (SolidColorBrush)GetValue(SeperatorColorProperty); }
set { SetValue(SeperatorColorProperty, value); }
}
public SolidColorBrush WorkingHourCellBackgroundColor
{
get { return (SolidColorBrush)GetValue(WorkingHourCellBackgroundColorProperty); }
set { SetValue(WorkingHourCellBackgroundColorProperty, value); }
}
public SolidColorBrush SelectedCellBackgroundBrush
{
get { return (SolidColorBrush)GetValue(SelectedCellBackgroundBrushProperty); }
set { SetValue(SelectedCellBackgroundBrushProperty, value); }
}
public DateTime? SelectedDateTime
{
get { return (DateTime?)GetValue(SelectedDateTimeProperty); }
set { SetValue(SelectedDateTimeProperty, value); }
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
Canvas = GetTemplateChild(PART_InternalCanvas) as CanvasControl;
// TODO: These will leak. Dispose them properly when needed.
Canvas.Draw += OnCanvasDraw;
Canvas.PointerPressed += OnCanvasPointerPressed;
ForceDraw();
}
private static void OnSelectedDateTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is WinoDayTimelineCanvas control)
{ {
get { return (UIElement)GetValue(PositionerUIElementProperty); } if (e.OldValue != null && e.NewValue == null)
set { SetValue(PositionerUIElementProperty, value); }
}
public CalendarRenderOptions RenderOptions
{
get { return (CalendarRenderOptions)GetValue(RenderOptionsProperty); }
set { SetValue(RenderOptionsProperty, value); }
}
public SolidColorBrush HalfHourSeperatorColor
{
get { return (SolidColorBrush)GetValue(HalfHourSeperatorColorProperty); }
set { SetValue(HalfHourSeperatorColorProperty, value); }
}
public SolidColorBrush SeperatorColor
{
get { return (SolidColorBrush)GetValue(SeperatorColorProperty); }
set { SetValue(SeperatorColorProperty, value); }
}
public SolidColorBrush WorkingHourCellBackgroundColor
{
get { return (SolidColorBrush)GetValue(WorkingHourCellBackgroundColorProperty); }
set { SetValue(WorkingHourCellBackgroundColorProperty, value); }
}
public SolidColorBrush SelectedCellBackgroundBrush
{
get { return (SolidColorBrush)GetValue(SelectedCellBackgroundBrushProperty); }
set { SetValue(SelectedCellBackgroundBrushProperty, value); }
}
public DateTime? SelectedDateTime
{
get { return (DateTime?)GetValue(SelectedDateTimeProperty); }
set { SetValue(SelectedDateTimeProperty, value); }
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
Canvas = GetTemplateChild(PART_InternalCanvas) as CanvasControl;
// TODO: These will leak. Dispose them properly when needed.
Canvas.Draw += OnCanvasDraw;
Canvas.PointerPressed += OnCanvasPointerPressed;
ForceDraw();
}
private static void OnSelectedDateTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is WinoDayTimelineCanvas control)
{ {
if (e.OldValue != null && e.NewValue == null) control.RaiseCellUnselected();
{
control.RaiseCellUnselected();
}
control.ForceDraw();
}
}
private void RaiseCellUnselected()
{
TimelineCellUnselected?.Invoke(this, new TimelineCellUnselectedArgs());
}
private void OnCanvasPointerPressed(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
if (RenderOptions == null) return;
var hourHeight = RenderOptions.CalendarSettings.HourHeight;
// When users click to cell we need to find the day, hour and minutes (first 30 minutes or second 30 minutes) that it represents on the timeline.
PointerPoint positionerRootPoint = e.GetCurrentPoint(PositionerUIElement);
PointerPoint canvasPointerPoint = e.GetCurrentPoint(Canvas);
Point touchPoint = canvasPointerPoint.Position;
var singleDayWidth = (Canvas.ActualWidth / RenderOptions.TotalDayCount);
int day = (int)(touchPoint.X / singleDayWidth);
int hour = (int)(touchPoint.Y / hourHeight);
bool isSecondHalf = touchPoint.Y % hourHeight > (hourHeight / 2);
var diffX = positionerRootPoint.Position.X - touchPoint.X;
var diffY = positionerRootPoint.Position.Y - touchPoint.Y;
var cellStartRelativePositionX = diffX + (day * singleDayWidth);
var cellEndRelativePositionX = cellStartRelativePositionX + singleDayWidth;
var cellStartRelativePositionY = diffY + (hour * hourHeight) + (isSecondHalf ? hourHeight / 2 : 0);
var cellEndRelativePositionY = cellStartRelativePositionY + (isSecondHalf ? (hourHeight / 2) : hourHeight);
var cellSize = new Size(cellEndRelativePositionX - cellStartRelativePositionX, hourHeight / 2);
var positionerPoint = new Point(cellStartRelativePositionX, cellStartRelativePositionY);
var clickedDateTime = RenderOptions.DateRange.StartDate.AddDays(day).AddHours(hour).AddMinutes(isSecondHalf ? 30 : 0);
// If there is already a selected date, in order to mimic the popup behavior, we need to dismiss the previous selection first.
// Next click will be a new selection.
// Raise the events directly here instead of DP to not lose pointer position.
if (clickedDateTime == SelectedDateTime || SelectedDateTime != null)
{
SelectedDateTime = null;
}
else
{
SelectedDateTime = clickedDateTime;
TimelineCellSelected?.Invoke(this, new TimelineCellSelectedArgs(clickedDateTime, touchPoint, positionerPoint, cellSize));
} }
Debug.WriteLine($"Clicked: {clickedDateTime}"); control.ForceDraw();
}
public WinoDayTimelineCanvas()
{
DefaultStyleKey = typeof(WinoDayTimelineCanvas);
}
private static void OnRenderingPropertiesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is WinoDayTimelineCanvas control)
{
control.ForceDraw();
}
}
private void ForceDraw() => Canvas?.Invalidate();
private bool CanDrawTimeline()
{
return RenderOptions != null
&& Canvas != null
&& Canvas.ReadyToDraw
&& WorkingHourCellBackgroundColor != null
&& SeperatorColor != null
&& HalfHourSeperatorColor != null
&& SelectedCellBackgroundBrush != null;
}
private void OnCanvasDraw(CanvasControl sender, CanvasDrawEventArgs args)
{
if (!CanDrawTimeline()) return;
int hours = 24;
double canvasWidth = Canvas.ActualWidth;
double canvasHeight = Canvas.ActualHeight;
if (canvasWidth == 0 || canvasHeight == 0) return;
// Calculate the width of each rectangle (1 day column)
// Equal distribution of the whole width.
double rectWidth = canvasWidth / RenderOptions.TotalDayCount;
// Calculate the height of each rectangle (1 hour row)
double rectHeight = RenderOptions.CalendarSettings.HourHeight;
// Define stroke and fill colors
var strokeColor = SeperatorColor.Color;
float strokeThickness = 0.5f;
for (int day = 0; day < RenderOptions.TotalDayCount; day++)
{
var currentDay = RenderOptions.DateRange.StartDate.AddDays(day);
bool isWorkingDay = RenderOptions.CalendarSettings.WorkingDays.Contains(currentDay.DayOfWeek);
// Loop through each hour (rows)
for (int hour = 0; hour < hours; hour++)
{
var renderTime = TimeSpan.FromHours(hour);
var representingDateTime = currentDay.AddHours(hour);
// Calculate the position and size of the rectangle
double x = day * rectWidth;
double y = hour * rectHeight;
var rectangle = new Rect(x, y, rectWidth, rectHeight);
// Draw the rectangle border.
// This is the main rectangle.
args.DrawingSession.DrawRectangle(rectangle, strokeColor, strokeThickness);
// Fill another rectangle with the working hour background color
// This rectangle must be placed with -1 margin to prevent invisible borders of the main rectangle.
if (isWorkingDay && renderTime >= RenderOptions.CalendarSettings.WorkingHourStart && renderTime <= RenderOptions.CalendarSettings.WorkingHourEnd)
{
var backgroundRectangle = new Rect(x + 1, y + 1, rectWidth - 1, rectHeight - 1);
args.DrawingSession.DrawRectangle(backgroundRectangle, strokeColor, strokeThickness);
args.DrawingSession.FillRectangle(backgroundRectangle, WorkingHourCellBackgroundColor.Color);
}
// Draw a line in the center of the rectangle for representing half hours.
double lineY = y + rectHeight / 2;
args.DrawingSession.DrawLine((float)x, (float)lineY, (float)(x + rectWidth), (float)lineY, HalfHourSeperatorColor.Color, strokeThickness, new CanvasStrokeStyle()
{
DashStyle = CanvasDashStyle.Dot
});
}
// Draw selected item background color for the date if possible.
if (SelectedDateTime != null)
{
var selectedDateTime = SelectedDateTime.Value;
if (selectedDateTime.Date == currentDay.Date)
{
var selectionRectHeight = rectHeight / 2;
var selectedY = selectedDateTime.Hour * rectHeight + (selectedDateTime.Minute / 60) * rectHeight;
// Second half of the hour is selected.
if (selectedDateTime.TimeOfDay.Minutes == 30)
{
selectedY += rectHeight / 2;
}
var selectedRectangle = new Rect(day * rectWidth, selectedY, rectWidth, selectionRectHeight);
args.DrawingSession.FillRectangle(selectedRectangle, SelectedCellBackgroundBrush.Color);
}
}
}
}
public void Dispose()
{
if (Canvas == null) return;
Canvas.Draw -= OnCanvasDraw;
Canvas.PointerPressed -= OnCanvasPointerPressed;
Canvas.RemoveFromVisualTree();
Canvas = null;
} }
} }
private void RaiseCellUnselected()
{
TimelineCellUnselected?.Invoke(this, new TimelineCellUnselectedArgs());
}
private void OnCanvasPointerPressed(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
if (RenderOptions == null) return;
var hourHeight = RenderOptions.CalendarSettings.HourHeight;
// When users click to cell we need to find the day, hour and minutes (first 30 minutes or second 30 minutes) that it represents on the timeline.
PointerPoint positionerRootPoint = e.GetCurrentPoint(PositionerUIElement);
PointerPoint canvasPointerPoint = e.GetCurrentPoint(Canvas);
Point touchPoint = canvasPointerPoint.Position;
var singleDayWidth = (Canvas.ActualWidth / RenderOptions.TotalDayCount);
int day = (int)(touchPoint.X / singleDayWidth);
int hour = (int)(touchPoint.Y / hourHeight);
bool isSecondHalf = touchPoint.Y % hourHeight > (hourHeight / 2);
var diffX = positionerRootPoint.Position.X - touchPoint.X;
var diffY = positionerRootPoint.Position.Y - touchPoint.Y;
var cellStartRelativePositionX = diffX + (day * singleDayWidth);
var cellEndRelativePositionX = cellStartRelativePositionX + singleDayWidth;
var cellStartRelativePositionY = diffY + (hour * hourHeight) + (isSecondHalf ? hourHeight / 2 : 0);
var cellEndRelativePositionY = cellStartRelativePositionY + (isSecondHalf ? (hourHeight / 2) : hourHeight);
var cellSize = new Size(cellEndRelativePositionX - cellStartRelativePositionX, hourHeight / 2);
var positionerPoint = new Point(cellStartRelativePositionX, cellStartRelativePositionY);
var clickedDateTime = RenderOptions.DateRange.StartDate.AddDays(day).AddHours(hour).AddMinutes(isSecondHalf ? 30 : 0);
// If there is already a selected date, in order to mimic the popup behavior, we need to dismiss the previous selection first.
// Next click will be a new selection.
// Raise the events directly here instead of DP to not lose pointer position.
if (clickedDateTime == SelectedDateTime || SelectedDateTime != null)
{
SelectedDateTime = null;
}
else
{
SelectedDateTime = clickedDateTime;
TimelineCellSelected?.Invoke(this, new TimelineCellSelectedArgs(clickedDateTime, touchPoint, positionerPoint, cellSize));
}
Debug.WriteLine($"Clicked: {clickedDateTime}");
}
public WinoDayTimelineCanvas()
{
DefaultStyleKey = typeof(WinoDayTimelineCanvas);
}
private static void OnRenderingPropertiesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is WinoDayTimelineCanvas control)
{
control.ForceDraw();
}
}
private void ForceDraw() => Canvas?.Invalidate();
private bool CanDrawTimeline()
{
return RenderOptions != null
&& Canvas != null
&& Canvas.ReadyToDraw
&& WorkingHourCellBackgroundColor != null
&& SeperatorColor != null
&& HalfHourSeperatorColor != null
&& SelectedCellBackgroundBrush != null;
}
private void OnCanvasDraw(CanvasControl sender, CanvasDrawEventArgs args)
{
if (!CanDrawTimeline()) return;
int hours = 24;
double canvasWidth = Canvas.ActualWidth;
double canvasHeight = Canvas.ActualHeight;
if (canvasWidth == 0 || canvasHeight == 0) return;
// Calculate the width of each rectangle (1 day column)
// Equal distribution of the whole width.
double rectWidth = canvasWidth / RenderOptions.TotalDayCount;
// Calculate the height of each rectangle (1 hour row)
double rectHeight = RenderOptions.CalendarSettings.HourHeight;
// Define stroke and fill colors
var strokeColor = SeperatorColor.Color;
float strokeThickness = 0.5f;
for (int day = 0; day < RenderOptions.TotalDayCount; day++)
{
var currentDay = RenderOptions.DateRange.StartDate.AddDays(day);
bool isWorkingDay = RenderOptions.CalendarSettings.WorkingDays.Contains(currentDay.DayOfWeek);
// Loop through each hour (rows)
for (int hour = 0; hour < hours; hour++)
{
var renderTime = TimeSpan.FromHours(hour);
var representingDateTime = currentDay.AddHours(hour);
// Calculate the position and size of the rectangle
double x = day * rectWidth;
double y = hour * rectHeight;
var rectangle = new Rect(x, y, rectWidth, rectHeight);
// Draw the rectangle border.
// This is the main rectangle.
args.DrawingSession.DrawRectangle(rectangle, strokeColor, strokeThickness);
// Fill another rectangle with the working hour background color
// This rectangle must be placed with -1 margin to prevent invisible borders of the main rectangle.
if (isWorkingDay && renderTime >= RenderOptions.CalendarSettings.WorkingHourStart && renderTime <= RenderOptions.CalendarSettings.WorkingHourEnd)
{
var backgroundRectangle = new Rect(x + 1, y + 1, rectWidth - 1, rectHeight - 1);
args.DrawingSession.DrawRectangle(backgroundRectangle, strokeColor, strokeThickness);
args.DrawingSession.FillRectangle(backgroundRectangle, WorkingHourCellBackgroundColor.Color);
}
// Draw a line in the center of the rectangle for representing half hours.
double lineY = y + rectHeight / 2;
args.DrawingSession.DrawLine((float)x, (float)lineY, (float)(x + rectWidth), (float)lineY, HalfHourSeperatorColor.Color, strokeThickness, new CanvasStrokeStyle()
{
DashStyle = CanvasDashStyle.Dot
});
}
// Draw selected item background color for the date if possible.
if (SelectedDateTime != null)
{
var selectedDateTime = SelectedDateTime.Value;
if (selectedDateTime.Date == currentDay.Date)
{
var selectionRectHeight = rectHeight / 2;
var selectedY = selectedDateTime.Hour * rectHeight + (selectedDateTime.Minute / 60) * rectHeight;
// Second half of the hour is selected.
if (selectedDateTime.TimeOfDay.Minutes == 30)
{
selectedY += rectHeight / 2;
}
var selectedRectangle = new Rect(day * rectWidth, selectedY, rectWidth, selectionRectHeight);
args.DrawingSession.FillRectangle(selectedRectangle, SelectedCellBackgroundBrush.Color);
}
}
}
}
public void Dispose()
{
if (Canvas == null) return;
Canvas.Draw -= OnCanvasDraw;
Canvas.PointerPressed -= OnCanvasPointerPressed;
Canvas.RemoveFromVisualTree();
Canvas = null;
}
} }

View File

@@ -10,98 +10,97 @@ using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Models.Calendar; using Wino.Core.Domain.Models.Calendar;
using Wino.Helpers; using Wino.Helpers;
namespace Wino.Calendar.Helpers namespace Wino.Calendar.Helpers;
public static class CalendarXamlHelpers
{ {
public static class CalendarXamlHelpers public static CalendarItemViewModel GetFirstAllDayEvent(CalendarEventCollection collection)
=> (CalendarItemViewModel)collection.AllDayEvents.FirstOrDefault();
/// <summary>
/// Returns full date + duration info in Event Details page details title.
/// </summary>
public static string GetEventDetailsDateString(CalendarItemViewModel calendarItemViewModel, CalendarSettings settings)
{ {
public static CalendarItemViewModel GetFirstAllDayEvent(CalendarEventCollection collection) if (calendarItemViewModel == null || settings == null) return string.Empty;
=> (CalendarItemViewModel)collection.AllDayEvents.FirstOrDefault();
/// <summary> var start = calendarItemViewModel.Period.Start;
/// Returns full date + duration info in Event Details page details title. var end = calendarItemViewModel.Period.End;
/// </summary>
public static string GetEventDetailsDateString(CalendarItemViewModel calendarItemViewModel, CalendarSettings settings) string timeFormat = settings.DayHeaderDisplayType == DayHeaderDisplayType.TwelveHour ? "h:mm tt" : "HH:mm";
string dateFormat = settings.DayHeaderDisplayType == DayHeaderDisplayType.TwelveHour ? "dddd, dd MMMM h:mm tt" : "dddd, dd MMMM HH:mm";
if (calendarItemViewModel.IsMultiDayEvent)
{ {
if (calendarItemViewModel == null || settings == null) return string.Empty; return $"{start.ToString($"dd MMMM ddd {timeFormat}", settings.CultureInfo)} - {end.ToString($"dd MMMM ddd {timeFormat}", settings.CultureInfo)}";
var start = calendarItemViewModel.Period.Start;
var end = calendarItemViewModel.Period.End;
string timeFormat = settings.DayHeaderDisplayType == DayHeaderDisplayType.TwelveHour ? "h:mm tt" : "HH:mm";
string dateFormat = settings.DayHeaderDisplayType == DayHeaderDisplayType.TwelveHour ? "dddd, dd MMMM h:mm tt" : "dddd, dd MMMM HH:mm";
if (calendarItemViewModel.IsMultiDayEvent)
{
return $"{start.ToString($"dd MMMM ddd {timeFormat}", settings.CultureInfo)} - {end.ToString($"dd MMMM ddd {timeFormat}", settings.CultureInfo)}";
}
else
{
return $"{start.ToString(dateFormat, settings.CultureInfo)} - {end.ToString(timeFormat, settings.CultureInfo)}";
}
} }
else
public static string GetRecurrenceString(CalendarItemViewModel calendarItemViewModel)
{ {
if (calendarItemViewModel == null || !calendarItemViewModel.IsRecurringChild) return string.Empty; return $"{start.ToString(dateFormat, settings.CultureInfo)} - {end.ToString(timeFormat, settings.CultureInfo)}";
// Parse recurrence rules
var calendarEvent = new CalendarEvent
{
Start = new CalDateTime(calendarItemViewModel.StartDate),
End = new CalDateTime(calendarItemViewModel.EndDate),
};
var recurrenceLines = Regex.Split(calendarItemViewModel.CalendarItem.Recurrence, Constants.CalendarEventRecurrenceRuleSeperator);
foreach (var line in recurrenceLines)
{
calendarEvent.RecurrenceRules.Add(new RecurrencePattern(line));
}
if (calendarEvent.RecurrenceRules == null || !calendarEvent.RecurrenceRules.Any())
{
return "No recurrence pattern.";
}
var recurrenceRule = calendarEvent.RecurrenceRules.First();
var daysOfWeek = string.Join(", ", recurrenceRule.ByDay.Select(day => day.DayOfWeek.ToString()));
string timeZone = calendarEvent.DtStart.TzId ?? "UTC";
return $"Every {daysOfWeek}, effective {calendarEvent.DtStart.Value.ToShortDateString()} " +
$"from {calendarEvent.DtStart.Value.ToShortTimeString()} to {calendarEvent.DtEnd.Value.ToShortTimeString()} " +
$"{timeZone}.";
}
public static string GetDetailsPopupDurationString(CalendarItemViewModel calendarItemViewModel, CalendarSettings settings)
{
if (calendarItemViewModel == null || settings == null) return string.Empty;
// Single event in a day.
if (!calendarItemViewModel.IsAllDayEvent && !calendarItemViewModel.IsMultiDayEvent)
{
return $"{calendarItemViewModel.Period.Start.ToString("d", settings.CultureInfo)} {settings.GetTimeString(calendarItemViewModel.Period.Duration)}";
}
else if (calendarItemViewModel.IsMultiDayEvent)
{
return $"{calendarItemViewModel.Period.Start.ToString("d", settings.CultureInfo)} - {calendarItemViewModel.Period.End.ToString("d", settings.CultureInfo)}";
}
else
{
// All day event.
return $"{calendarItemViewModel.Period.Start.ToString("d", settings.CultureInfo)} ({Translator.CalendarItemAllDay})";
}
}
public static PopupPlacementMode GetDesiredPlacementModeForEventsDetailsPopup(
CalendarItemViewModel calendarItemViewModel,
CalendarDisplayType calendarDisplayType)
{
if (calendarItemViewModel == null) return PopupPlacementMode.Auto;
// All and/or multi day events always go to the top of the screen.
if (calendarItemViewModel.IsAllDayEvent || calendarItemViewModel.IsMultiDayEvent) return PopupPlacementMode.Bottom;
return XamlHelpers.GetPlaccementModeForCalendarType(calendarDisplayType);
} }
} }
public static string GetRecurrenceString(CalendarItemViewModel calendarItemViewModel)
{
if (calendarItemViewModel == null || !calendarItemViewModel.IsRecurringChild) return string.Empty;
// Parse recurrence rules
var calendarEvent = new CalendarEvent
{
Start = new CalDateTime(calendarItemViewModel.StartDate),
End = new CalDateTime(calendarItemViewModel.EndDate),
};
var recurrenceLines = Regex.Split(calendarItemViewModel.CalendarItem.Recurrence, Constants.CalendarEventRecurrenceRuleSeperator);
foreach (var line in recurrenceLines)
{
calendarEvent.RecurrenceRules.Add(new RecurrencePattern(line));
}
if (calendarEvent.RecurrenceRules == null || !calendarEvent.RecurrenceRules.Any())
{
return "No recurrence pattern.";
}
var recurrenceRule = calendarEvent.RecurrenceRules.First();
var daysOfWeek = string.Join(", ", recurrenceRule.ByDay.Select(day => day.DayOfWeek.ToString()));
string timeZone = calendarEvent.DtStart.TzId ?? "UTC";
return $"Every {daysOfWeek}, effective {calendarEvent.DtStart.Value.ToShortDateString()} " +
$"from {calendarEvent.DtStart.Value.ToShortTimeString()} to {calendarEvent.DtEnd.Value.ToShortTimeString()} " +
$"{timeZone}.";
}
public static string GetDetailsPopupDurationString(CalendarItemViewModel calendarItemViewModel, CalendarSettings settings)
{
if (calendarItemViewModel == null || settings == null) return string.Empty;
// Single event in a day.
if (!calendarItemViewModel.IsAllDayEvent && !calendarItemViewModel.IsMultiDayEvent)
{
return $"{calendarItemViewModel.Period.Start.ToString("d", settings.CultureInfo)} {settings.GetTimeString(calendarItemViewModel.Period.Duration)}";
}
else if (calendarItemViewModel.IsMultiDayEvent)
{
return $"{calendarItemViewModel.Period.Start.ToString("d", settings.CultureInfo)} - {calendarItemViewModel.Period.End.ToString("d", settings.CultureInfo)}";
}
else
{
// All day event.
return $"{calendarItemViewModel.Period.Start.ToString("d", settings.CultureInfo)} ({Translator.CalendarItemAllDay})";
}
}
public static PopupPlacementMode GetDesiredPlacementModeForEventsDetailsPopup(
CalendarItemViewModel calendarItemViewModel,
CalendarDisplayType calendarDisplayType)
{
if (calendarItemViewModel == null) return PopupPlacementMode.Auto;
// All and/or multi day events always go to the top of the screen.
if (calendarItemViewModel.IsAllDayEvent || calendarItemViewModel.IsMultiDayEvent) return PopupPlacementMode.Bottom;
return XamlHelpers.GetPlaccementModeForCalendarType(calendarDisplayType);
}
} }

View File

@@ -15,16 +15,15 @@ using Windows.UI.Xaml.Navigation;
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 // The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace Wino.Calendar namespace Wino.Calendar;
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{ {
/// <summary> public MainPage()
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{ {
public MainPage() this.InitializeComponent();
{
this.InitializeComponent();
}
} }
} }

View File

@@ -1,17 +1,16 @@
namespace Wino.Calendar.Models namespace Wino.Calendar.Models;
public struct CalendarItemMeasurement
{ {
public struct CalendarItemMeasurement // Where to start?
public double Left { get; set; }
// Extend until where?
public double Right { get; set; }
public CalendarItemMeasurement(double left, double right)
{ {
// Where to start? Left = left;
public double Left { get; set; } Right = right;
// Extend until where?
public double Right { get; set; }
public CalendarItemMeasurement(double left, double right)
{
Left = left;
Right = right;
}
} }
} }

View File

@@ -8,6 +8,11 @@
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
IgnorableNamespaces="uap mp"> IgnorableNamespaces="uap mp">
<Identity
Name="58272BurakKSE.WinoCalendar"
Publisher="CN=51FBDAF3-E212-4149-89A2-A2636B3BC911"
Version="1.0.15.0" />
<!-- Publisher Cache Folders --> <!-- Publisher Cache Folders -->
<Extensions> <Extensions>
<Extension Category="windows.publisherCacheFolders"> <Extension Category="windows.publisherCacheFolders">
@@ -16,13 +21,8 @@
</PublisherCacheFolders> </PublisherCacheFolders>
</Extension> </Extension>
</Extensions> </Extensions>
<Identity
Name="58272BurakKSE.WinoCalendar"
Publisher="CN=51FBDAF3-E212-4149-89A2-A2636B3BC911"
Version="1.0.15.0" />
<mp:PhoneIdentity PhoneProductId="f047b7dd-96ec-4d54-a862-9321e271e449" PhonePublisherId="00000000-0000-0000-0000-000000000000"/> <mp:PhoneIdentity PhoneProductId="f047b7dd-96ec-4d54-a862-9321e271e449" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
<Properties> <Properties>
<DisplayName>Wino Calendar</DisplayName> <DisplayName>Wino Calendar</DisplayName>

View File

@@ -1,29 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Wino.Calendar")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Wino.Calendar")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: ComVisible(false)]

View File

@@ -1,44 +0,0 @@
<!--
This file contains Runtime Directives used by .NET Native. The defaults here are suitable for most
developers. However, you can modify these parameters to modify the behavior of the .NET Native
optimizer.
Runtime Directives are documented at https://go.microsoft.com/fwlink/?LinkID=391919
To fully enable reflection for App1.MyClass and all of its public/private members
<Type Name="App1.MyClass" Dynamic="Required All"/>
To enable dynamic creation of the specific instantiation of AppClass<T> over System.Int32
<TypeInstantiation Name="App1.AppClass" Arguments="System.Int32" Activate="Required Public" />
Using the Namespace directive to apply reflection policy to all the types in a particular namespace
<Namespace Name="DataClasses.ViewModels" Serialize="All" />
-->
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Application>
<!--
An Assembly element with Name="*Application*" applies to all assemblies in
the application package. The asterisks are not wildcards.
-->
<Assembly Name="*Application*" Dynamic="Required All" />
<!-- Reduce memory footprint when building with Microsoft.Graph -->
<Assembly Name="Microsoft.Graph" Serialize="Excluded" />
<Assembly Name="Microsoft.Kiota.Abstractions" Dynamic="Public" />
<Assembly Name="Microsoft.Kiota.Authentication.Azure" Dynamic="Public" />
<Assembly Name="Microsoft.Kiota.Http.HttpClientLibrary" Dynamic="Public" />
<Assembly Name="Microsoft.Kiota.Serialization.Form" Dynamic="Public" />
<Assembly Name="Microsoft.Kiota.Serialization.Json" Dynamic="Public" />
<Assembly Name="Microsoft.Kiota.Serialization.Multipart" Dynamic="Public" />
<!-- Add your application specific runtime directives here. -->
<Type Name="Windows.Foundation.TypedEventHandler{Microsoft.UI.Xaml.Controls.NavigationView,Microsoft.UI.Xaml.Controls.NavigationViewItemInvokedEventArgs}" MarshalObject="Public" />
<Type Name="Microsoft.UI.Xaml.Controls.NavigationView">
<Event Name="ItemInvoked" Dynamic="Required"/>
</Type>
</Application>
</Directives>

View File

@@ -0,0 +1,7 @@
{
"profiles": {
"Wino.Calendar": {
"commandName": "MsixPackage"
}
}
}

View File

@@ -2,21 +2,20 @@
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Wino.Calendar.ViewModels.Data; using Wino.Calendar.ViewModels.Data;
namespace Wino.Calendar.Selectors namespace Wino.Calendar.Selectors;
public partial class CustomAreaCalendarItemSelector : DataTemplateSelector
{ {
public class CustomAreaCalendarItemSelector : DataTemplateSelector public DataTemplate AllDayTemplate { get; set; }
public DataTemplate MultiDayTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{ {
public DataTemplate AllDayTemplate { get; set; } if (item is CalendarItemViewModel calendarItemViewModel)
public DataTemplate MultiDayTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{ {
if (item is CalendarItemViewModel calendarItemViewModel) return calendarItemViewModel.IsMultiDayEvent ? MultiDayTemplate : AllDayTemplate;
{
return calendarItemViewModel.IsMultiDayEvent ? MultiDayTemplate : AllDayTemplate;
}
return base.SelectTemplateCore(item, container);
} }
return base.SelectTemplateCore(item, container);
} }
} }

View File

@@ -2,33 +2,32 @@
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Wino.Core.Domain.Enums; using Wino.Core.Domain.Enums;
namespace Wino.Calendar.Selectors namespace Wino.Calendar.Selectors;
public partial class WinoCalendarItemTemplateSelector : DataTemplateSelector
{ {
public class WinoCalendarItemTemplateSelector : DataTemplateSelector public CalendarDisplayType DisplayType { get; set; }
public DataTemplate DayWeekWorkWeekTemplate { get; set; }
public DataTemplate MonthlyTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{ {
public CalendarDisplayType DisplayType { get; set; } switch (DisplayType)
public DataTemplate DayWeekWorkWeekTemplate { get; set; }
public DataTemplate MonthlyTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{ {
switch (DisplayType) case CalendarDisplayType.Day:
{ case CalendarDisplayType.Week:
case CalendarDisplayType.Day: case CalendarDisplayType.WorkWeek:
case CalendarDisplayType.Week: return DayWeekWorkWeekTemplate;
case CalendarDisplayType.WorkWeek: case CalendarDisplayType.Month:
return DayWeekWorkWeekTemplate; return MonthlyTemplate;
case CalendarDisplayType.Month: case CalendarDisplayType.Year:
return MonthlyTemplate; break;
case CalendarDisplayType.Year: default:
break; break;
default:
break;
}
return base.SelectTemplateCore(item, container);
} }
return base.SelectTemplateCore(item, container);
} }
} }

View File

@@ -7,108 +7,107 @@ using Wino.Calendar.ViewModels.Data;
using Wino.Calendar.ViewModels.Interfaces; using Wino.Calendar.ViewModels.Interfaces;
using Wino.Core.Domain.Entities.Shared; using Wino.Core.Domain.Entities.Shared;
namespace Wino.Calendar.Services namespace Wino.Calendar.Services;
/// <summary>
/// Encapsulated state manager for collectively managing the state of account calendars.
/// Callers must react to the events to update their state only from this service.
/// </summary>
public partial class AccountCalendarStateService : ObservableObject, IAccountCalendarStateService
{ {
/// <summary> public event EventHandler<GroupedAccountCalendarViewModel> CollectiveAccountGroupSelectionStateChanged;
/// Encapsulated state manager for collectively managing the state of account calendars. public event EventHandler<AccountCalendarViewModel> AccountCalendarSelectionStateChanged;
/// Callers must react to the events to update their state only from this service.
/// </summary> [ObservableProperty]
public partial class AccountCalendarStateService : ObservableObject, IAccountCalendarStateService public partial ReadOnlyObservableCollection<GroupedAccountCalendarViewModel> GroupedAccountCalendars { get; set; }
private ObservableCollection<GroupedAccountCalendarViewModel> _internalGroupedAccountCalendars = new ObservableCollection<GroupedAccountCalendarViewModel>();
public IEnumerable<AccountCalendarViewModel> ActiveCalendars
{ {
public event EventHandler<GroupedAccountCalendarViewModel> CollectiveAccountGroupSelectionStateChanged; get
public event EventHandler<AccountCalendarViewModel> AccountCalendarSelectionStateChanged;
[ObservableProperty]
private ReadOnlyObservableCollection<GroupedAccountCalendarViewModel> groupedAccountCalendars;
private ObservableCollection<GroupedAccountCalendarViewModel> _internalGroupedAccountCalendars = new ObservableCollection<GroupedAccountCalendarViewModel>();
public IEnumerable<AccountCalendarViewModel> ActiveCalendars
{ {
get return GroupedAccountCalendars
{ .SelectMany(a => a.AccountCalendars)
return GroupedAccountCalendars .Where(b => b.IsChecked);
.SelectMany(a => a.AccountCalendars)
.Where(b => b.IsChecked);
}
} }
}
public IEnumerable<IGrouping<MailAccount, AccountCalendarViewModel>> GroupedAccountCalendarsEnumerable public IEnumerable<IGrouping<MailAccount, AccountCalendarViewModel>> GroupedAccountCalendarsEnumerable
{
get
{ {
get return GroupedAccountCalendars
{ .Select(a => a.AccountCalendars)
return GroupedAccountCalendars .SelectMany(b => b)
.Select(a => a.AccountCalendars) .GroupBy(c => c.Account);
.SelectMany(b => b)
.GroupBy(c => c.Account);
}
} }
}
public AccountCalendarStateService() public AccountCalendarStateService()
{
GroupedAccountCalendars = new ReadOnlyObservableCollection<GroupedAccountCalendarViewModel>(_internalGroupedAccountCalendars);
}
private void SingleGroupCalendarCollectiveStateChanged(object sender, EventArgs e)
=> CollectiveAccountGroupSelectionStateChanged?.Invoke(this, sender as GroupedAccountCalendarViewModel);
private void SingleCalendarSelectionStateChanged(object sender, AccountCalendarViewModel e)
=> AccountCalendarSelectionStateChanged?.Invoke(this, e);
public void AddGroupedAccountCalendar(GroupedAccountCalendarViewModel groupedAccountCalendar)
{
groupedAccountCalendar.CalendarSelectionStateChanged += SingleCalendarSelectionStateChanged;
groupedAccountCalendar.CollectiveSelectionStateChanged += SingleGroupCalendarCollectiveStateChanged;
_internalGroupedAccountCalendars.Add(groupedAccountCalendar);
}
public void RemoveGroupedAccountCalendar(GroupedAccountCalendarViewModel groupedAccountCalendar)
{
groupedAccountCalendar.CalendarSelectionStateChanged -= SingleCalendarSelectionStateChanged;
groupedAccountCalendar.CollectiveSelectionStateChanged -= SingleGroupCalendarCollectiveStateChanged;
_internalGroupedAccountCalendars.Remove(groupedAccountCalendar);
}
public void ClearGroupedAccountCalendar()
{
foreach (var groupedAccountCalendar in _internalGroupedAccountCalendars)
{ {
GroupedAccountCalendars = new ReadOnlyObservableCollection<GroupedAccountCalendarViewModel>(_internalGroupedAccountCalendars); RemoveGroupedAccountCalendar(groupedAccountCalendar);
} }
}
private void SingleGroupCalendarCollectiveStateChanged(object sender, EventArgs e) public void AddAccountCalendar(AccountCalendarViewModel accountCalendar)
=> CollectiveAccountGroupSelectionStateChanged?.Invoke(this, sender as GroupedAccountCalendarViewModel); {
// Find the group that this calendar belongs to.
var group = _internalGroupedAccountCalendars.FirstOrDefault(g => g.Account.Id == accountCalendar.Account.Id);
private void SingleCalendarSelectionStateChanged(object sender, AccountCalendarViewModel e) if (group == null)
=> AccountCalendarSelectionStateChanged?.Invoke(this, e);
public void AddGroupedAccountCalendar(GroupedAccountCalendarViewModel groupedAccountCalendar)
{ {
groupedAccountCalendar.CalendarSelectionStateChanged += SingleCalendarSelectionStateChanged; // If the group doesn't exist, create it.
groupedAccountCalendar.CollectiveSelectionStateChanged += SingleGroupCalendarCollectiveStateChanged; group = new GroupedAccountCalendarViewModel(accountCalendar.Account, new[] { accountCalendar });
AddGroupedAccountCalendar(group);
_internalGroupedAccountCalendars.Add(groupedAccountCalendar);
} }
else
public void RemoveGroupedAccountCalendar(GroupedAccountCalendarViewModel groupedAccountCalendar)
{ {
groupedAccountCalendar.CalendarSelectionStateChanged -= SingleCalendarSelectionStateChanged; group.AccountCalendars.Add(accountCalendar);
groupedAccountCalendar.CollectiveSelectionStateChanged -= SingleGroupCalendarCollectiveStateChanged;
_internalGroupedAccountCalendars.Remove(groupedAccountCalendar);
} }
}
public void ClearGroupedAccountCalendar() public void RemoveAccountCalendar(AccountCalendarViewModel accountCalendar)
{
var group = _internalGroupedAccountCalendars.FirstOrDefault(g => g.Account.Id == accountCalendar.Account.Id);
// We don't expect but just in case.
if (group == null) return;
group.AccountCalendars.Remove(accountCalendar);
if (group.AccountCalendars.Count == 0)
{ {
foreach (var groupedAccountCalendar in _internalGroupedAccountCalendars) RemoveGroupedAccountCalendar(group);
{
RemoveGroupedAccountCalendar(groupedAccountCalendar);
}
}
public void AddAccountCalendar(AccountCalendarViewModel accountCalendar)
{
// Find the group that this calendar belongs to.
var group = _internalGroupedAccountCalendars.FirstOrDefault(g => g.Account.Id == accountCalendar.Account.Id);
if (group == null)
{
// If the group doesn't exist, create it.
group = new GroupedAccountCalendarViewModel(accountCalendar.Account, new[] { accountCalendar });
AddGroupedAccountCalendar(group);
}
else
{
group.AccountCalendars.Add(accountCalendar);
}
}
public void RemoveAccountCalendar(AccountCalendarViewModel accountCalendar)
{
var group = _internalGroupedAccountCalendars.FirstOrDefault(g => g.Account.Id == accountCalendar.Account.Id);
// We don't expect but just in case.
if (group == null) return;
group.AccountCalendars.Remove(accountCalendar);
if (group.AccountCalendars.Count == 0)
{
RemoveGroupedAccountCalendar(group);
}
} }
} }
} }

View File

@@ -2,14 +2,13 @@
using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Interfaces;
using Wino.Core.UWP.Services; using Wino.Core.UWP.Services;
namespace Wino.Calendar.Services namespace Wino.Calendar.Services;
public class DialogService : DialogServiceBase, ICalendarDialogService
{ {
public class DialogService : DialogServiceBase, ICalendarDialogService public DialogService(IThemeService themeService,
IConfigurationService configurationService,
IApplicationResourceManager<ResourceDictionary> applicationResourceManager) : base(themeService, configurationService, applicationResourceManager)
{ {
public DialogService(IThemeService themeService,
IConfigurationService configurationService,
IApplicationResourceManager<ResourceDictionary> applicationResourceManager) : base(themeService, configurationService, applicationResourceManager)
{
}
} }
} }

View File

@@ -10,54 +10,53 @@ using Wino.Core.Domain.Models.Navigation;
using Wino.Core.UWP.Services; using Wino.Core.UWP.Services;
using Wino.Views; using Wino.Views;
namespace Wino.Calendar.Services namespace Wino.Calendar.Services;
public class NavigationService : NavigationServiceBase, INavigationService
{ {
public class NavigationService : NavigationServiceBase, INavigationService public Type GetPageType(WinoPage winoPage)
{ {
public Type GetPageType(WinoPage winoPage) return winoPage switch
{ {
return winoPage switch WinoPage.CalendarPage => typeof(CalendarPage),
{ WinoPage.SettingsPage => typeof(SettingsPage),
WinoPage.CalendarPage => typeof(CalendarPage), WinoPage.CalendarSettingsPage => typeof(CalendarSettingsPage),
WinoPage.SettingsPage => typeof(SettingsPage), WinoPage.AccountManagementPage => typeof(AccountManagementPage),
WinoPage.CalendarSettingsPage => typeof(CalendarSettingsPage), WinoPage.ManageAccountsPage => typeof(ManageAccountsPage),
WinoPage.AccountManagementPage => typeof(AccountManagementPage), WinoPage.PersonalizationPage => typeof(PersonalizationPage),
WinoPage.ManageAccountsPage => typeof(ManageAccountsPage), WinoPage.AccountDetailsPage => typeof(AccountDetailsPage),
WinoPage.PersonalizationPage => typeof(PersonalizationPage), WinoPage.EventDetailsPage => typeof(EventDetailsPage),
WinoPage.AccountDetailsPage => typeof(AccountDetailsPage), _ => throw new Exception("Page is not implemented yet."),
WinoPage.EventDetailsPage => typeof(EventDetailsPage), };
_ => throw new Exception("Page is not implemented yet."), }
};
}
public void GoBack() public void GoBack()
{
if (Window.Current.Content is Frame appFrame && appFrame.Content is AppShell shellPage)
{ {
if (Window.Current.Content is Frame appFrame && appFrame.Content is AppShell shellPage) var shellFrame = shellPage.GetShellFrame();
{
var shellFrame = shellPage.GetShellFrame();
if (shellFrame.CanGoBack) if (shellFrame.CanGoBack)
{ {
shellFrame.GoBack(); shellFrame.GoBack();
}
} }
} }
}
public bool Navigate(WinoPage page, object parameter = null, NavigationReferenceFrame frame = NavigationReferenceFrame.ShellFrame, NavigationTransitionType transition = NavigationTransitionType.None)
{ public bool Navigate(WinoPage page, object parameter = null, NavigationReferenceFrame frame = NavigationReferenceFrame.ShellFrame, NavigationTransitionType transition = NavigationTransitionType.None)
// All navigations are performed on shell frame for calendar. {
// All navigations are performed on shell frame for calendar.
if (Window.Current.Content is Frame appFrame && appFrame.Content is AppShell shellPage)
{ if (Window.Current.Content is Frame appFrame && appFrame.Content is AppShell shellPage)
var shellFrame = shellPage.GetShellFrame(); {
var shellFrame = shellPage.GetShellFrame();
var pageType = GetPageType(page);
var pageType = GetPageType(page);
shellFrame.Navigate(pageType, parameter);
return true; shellFrame.Navigate(pageType, parameter);
} return true;
}
return false;
} return false;
} }
} }

View File

@@ -4,33 +4,32 @@ using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.Accounts; using Wino.Core.Domain.Models.Accounts;
namespace Wino.Calendar.Services namespace Wino.Calendar.Services;
public class ProviderService : IProviderService
{ {
public class ProviderService : IProviderService public IProviderDetail GetProviderDetail(MailProviderType type)
{ {
public IProviderDetail GetProviderDetail(MailProviderType type) var details = GetAvailableProviders();
{
var details = GetAvailableProviders();
return details.FirstOrDefault(a => a.Type == type); return details.FirstOrDefault(a => a.Type == type);
}
public List<IProviderDetail> GetAvailableProviders()
{
var providerList = new List<IProviderDetail>();
var providers = new MailProviderType[]
{
MailProviderType.Outlook,
MailProviderType.Gmail
};
foreach (var type in providers)
{
providerList.Add(new ProviderDetail(type, SpecialImapProvider.None));
} }
public List<IProviderDetail> GetAvailableProviders() return providerList;
{
var providerList = new List<IProviderDetail>();
var providers = new MailProviderType[]
{
MailProviderType.Outlook,
MailProviderType.Gmail
};
foreach (var type in providers)
{
providerList.Add(new ProviderDetail(type, SpecialImapProvider.None));
}
return providerList;
}
} }
} }

File diff suppressed because one or more lines are too long

View File

@@ -1,12 +1,11 @@
using Windows.UI.Xaml; using Windows.UI.Xaml;
namespace Wino.Calendar.Styles namespace Wino.Calendar.Styles;
public sealed partial class WinoCalendarResources : ResourceDictionary
{ {
public sealed partial class WinoCalendarResources : ResourceDictionary public WinoCalendarResources()
{ {
public WinoCalendarResources() this.InitializeComponent();
{
this.InitializeComponent();
}
} }
} }

View File

@@ -1,7 +1,6 @@
using Wino.Calendar.ViewModels; using Wino.Calendar.ViewModels;
using Wino.Core.UWP; using Wino.Core.UWP;
namespace Wino.Calendar.Views.Abstract namespace Wino.Calendar.Views.Abstract;
{
public abstract class AccountDetailsPageAbstract : BasePage<AccountDetailsPageViewModel> { } public abstract class AccountDetailsPageAbstract : BasePage<AccountDetailsPageViewModel> { }
}

View File

@@ -1,7 +1,6 @@
using Wino.Calendar.ViewModels; using Wino.Calendar.ViewModels;
using Wino.Core.UWP; using Wino.Core.UWP;
namespace Wino.Calendar.Views.Abstract namespace Wino.Calendar.Views.Abstract;
{
public class AccountManagementPageAbstract : BasePage<AccountManagementViewModel> { } public partial class AccountManagementPageAbstract : BasePage<AccountManagementViewModel> { }
}

View File

@@ -1,7 +1,6 @@
using Wino.Calendar.ViewModels; using Wino.Calendar.ViewModels;
using Wino.Core.UWP; using Wino.Core.UWP;
namespace Wino.Calendar.Views.Abstract namespace Wino.Calendar.Views.Abstract;
{
public abstract class AppShellAbstract : BasePage<AppShellViewModel> { } public abstract class AppShellAbstract : BasePage<AppShellViewModel> { }
}

View File

@@ -1,7 +1,6 @@
using Wino.Calendar.ViewModels; using Wino.Calendar.ViewModels;
using Wino.Core.UWP; using Wino.Core.UWP;
namespace Wino.Calendar.Views.Abstract namespace Wino.Calendar.Views.Abstract;
{
public abstract class CalendarPageAbstract : BasePage<CalendarPageViewModel> { } public abstract class CalendarPageAbstract : BasePage<CalendarPageViewModel> { }
}

View File

@@ -1,7 +1,6 @@
using Wino.Calendar.ViewModels; using Wino.Calendar.ViewModels;
using Wino.Core.UWP; using Wino.Core.UWP;
namespace Wino.Calendar.Views.Abstract namespace Wino.Calendar.Views.Abstract;
{
public abstract class CalendarSettingsPageAbstract : BasePage<CalendarSettingsPageViewModel> { } public abstract class CalendarSettingsPageAbstract : BasePage<CalendarSettingsPageViewModel> { }
}

View File

@@ -1,7 +1,6 @@
using Wino.Calendar.ViewModels; using Wino.Calendar.ViewModels;
using Wino.Core.UWP; using Wino.Core.UWP;
namespace Wino.Calendar.Views.Abstract namespace Wino.Calendar.Views.Abstract;
{
public abstract class EventDetailsPageAbstract : BasePage<EventDetailsPageViewModel> { } public abstract class EventDetailsPageAbstract : BasePage<EventDetailsPageViewModel> { }
}

View File

@@ -1,7 +1,6 @@
using Wino.Core.UWP; using Wino.Core.UWP;
using Wino.Core.ViewModels; using Wino.Core.ViewModels;
namespace Wino.Calendar.Views.Abstract namespace Wino.Calendar.Views.Abstract;
{
public class PersonalizationPageAbstract : BasePage<PersonalizationPageViewModel> { } public partial class PersonalizationPageAbstract : BasePage<PersonalizationPageViewModel> { }
}

View File

@@ -1,12 +1,11 @@
using Wino.Calendar.Views.Abstract; using Wino.Calendar.Views.Abstract;
namespace Wino.Calendar.Views.Account namespace Wino.Calendar.Views.Account;
public sealed partial class AccountManagementPage : AccountManagementPageAbstract
{ {
public sealed partial class AccountManagementPage : AccountManagementPageAbstract public AccountManagementPage()
{ {
public AccountManagementPage() InitializeComponent();
{
InitializeComponent();
}
} }
} }

View File

@@ -5,50 +5,49 @@ using Wino.Calendar.Views.Abstract;
using Wino.Core.UWP; using Wino.Core.UWP;
using Wino.Messaging.Client.Calendar; using Wino.Messaging.Client.Calendar;
namespace Wino.Calendar.Views namespace Wino.Calendar.Views;
public sealed partial class AppShell : AppShellAbstract,
IRecipient<CalendarDisplayTypeChangedMessage>
{ {
public sealed partial class AppShell : AppShellAbstract, private const string STATE_HorizontalCalendar = "HorizontalCalendar";
IRecipient<CalendarDisplayTypeChangedMessage> private const string STATE_VerticalCalendar = "VerticalCalendar";
public Frame GetShellFrame() => ShellFrame;
public AppShell()
{ {
private const string STATE_HorizontalCalendar = "HorizontalCalendar"; InitializeComponent();
private const string STATE_VerticalCalendar = "VerticalCalendar";
public Frame GetShellFrame() => ShellFrame; Window.Current.SetTitleBar(DragArea);
ManageCalendarDisplayType();
public AppShell()
{
InitializeComponent();
Window.Current.SetTitleBar(DragArea);
ManageCalendarDisplayType();
}
private void ManageCalendarDisplayType()
{
// Go to different states based on the display type.
if (ViewModel.IsVerticalCalendar)
{
VisualStateManager.GoToState(this, STATE_VerticalCalendar, false);
}
else
{
VisualStateManager.GoToState(this, STATE_HorizontalCalendar, false);
}
}
private void PreviousDateClicked(object sender, RoutedEventArgs e) => WeakReferenceMessenger.Default.Send(new GoPreviousDateRequestedMessage());
private void NextDateClicked(object sender, RoutedEventArgs e) => WeakReferenceMessenger.Default.Send(new GoNextDateRequestedMessage());
public void Receive(CalendarDisplayTypeChangedMessage message)
{
ManageCalendarDisplayType();
}
private void ShellFrameContentNavigated(object sender, Windows.UI.Xaml.Navigation.NavigationEventArgs e)
=> RealAppBar.ShellFrameContent = (e.Content as BasePage).ShellContent;
private void AppBarBackButtonClicked(Core.UWP.Controls.WinoAppTitleBar sender, RoutedEventArgs args)
=> ViewModel.NavigationService.GoBack();
} }
private void ManageCalendarDisplayType()
{
// Go to different states based on the display type.
if (ViewModel.IsVerticalCalendar)
{
VisualStateManager.GoToState(this, STATE_VerticalCalendar, false);
}
else
{
VisualStateManager.GoToState(this, STATE_HorizontalCalendar, false);
}
}
private void PreviousDateClicked(object sender, RoutedEventArgs e) => WeakReferenceMessenger.Default.Send(new GoPreviousDateRequestedMessage());
private void NextDateClicked(object sender, RoutedEventArgs e) => WeakReferenceMessenger.Default.Send(new GoNextDateRequestedMessage());
public void Receive(CalendarDisplayTypeChangedMessage message)
{
ManageCalendarDisplayType();
}
private void ShellFrameContentNavigated(object sender, Windows.UI.Xaml.Navigation.NavigationEventArgs e)
=> RealAppBar.ShellFrameContent = (e.Content as BasePage).ShellContent;
private void AppBarBackButtonClicked(Core.UWP.Controls.WinoAppTitleBar sender, RoutedEventArgs args)
=> ViewModel.NavigationService.GoBack();
} }

View File

@@ -9,153 +9,152 @@ using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Models.Calendar; using Wino.Core.Domain.Models.Calendar;
using Wino.Messaging.Client.Calendar; using Wino.Messaging.Client.Calendar;
namespace Wino.Calendar.Views namespace Wino.Calendar.Views;
public sealed partial class CalendarPage : CalendarPageAbstract,
IRecipient<ScrollToDateMessage>,
IRecipient<ScrollToHourMessage>,
IRecipient<GoNextDateRequestedMessage>,
IRecipient<GoPreviousDateRequestedMessage>
{ {
public sealed partial class CalendarPage : CalendarPageAbstract, private const int PopupDialogOffset = 12;
IRecipient<ScrollToDateMessage>,
IRecipient<ScrollToHourMessage>, public CalendarPage()
IRecipient<GoNextDateRequestedMessage>,
IRecipient<GoPreviousDateRequestedMessage>
{ {
private const int PopupDialogOffset = 12; InitializeComponent();
NavigationCacheMode = NavigationCacheMode.Enabled;
public CalendarPage() ViewModel.DetailsShowCalendarItemChanged += CalendarItemDetailContextChanged;
}
private void CalendarItemDetailContextChanged(object sender, EventArgs e)
{
if (ViewModel.DisplayDetailsCalendarItemViewModel != null)
{ {
InitializeComponent(); var control = CalendarControl.GetCalendarItemControl(ViewModel.DisplayDetailsCalendarItemViewModel);
NavigationCacheMode = NavigationCacheMode.Enabled;
ViewModel.DetailsShowCalendarItemChanged += CalendarItemDetailContextChanged; if (control != null)
}
private void CalendarItemDetailContextChanged(object sender, EventArgs e)
{
if (ViewModel.DisplayDetailsCalendarItemViewModel != null)
{ {
var control = CalendarControl.GetCalendarItemControl(ViewModel.DisplayDetailsCalendarItemViewModel); EventDetailsPopup.PlacementTarget = control;
if (control != null)
{
EventDetailsPopup.PlacementTarget = control;
}
} }
} }
}
public void Receive(ScrollToHourMessage message) => CalendarControl.NavigateToHour(message.TimeSpan);
public void Receive(ScrollToDateMessage message) => CalendarControl.NavigateToDay(message.Date); public void Receive(ScrollToHourMessage message) => CalendarControl.NavigateToHour(message.TimeSpan);
public void Receive(GoNextDateRequestedMessage message) => CalendarControl.GoNextRange(); public void Receive(ScrollToDateMessage message) => CalendarControl.NavigateToDay(message.Date);
public void Receive(GoPreviousDateRequestedMessage message) => CalendarControl.GoPreviousRange(); public void Receive(GoNextDateRequestedMessage message) => CalendarControl.GoNextRange();
public void Receive(GoPreviousDateRequestedMessage message) => CalendarControl.GoPreviousRange();
protected override void OnNavigatedTo(NavigationEventArgs e)
{ protected override void OnNavigatedTo(NavigationEventArgs e)
base.OnNavigatedTo(e); {
base.OnNavigatedTo(e);
if (e.NavigationMode == NavigationMode.Back) return;
if (e.NavigationMode == NavigationMode.Back) return;
if (e.Parameter is CalendarPageNavigationArgs args)
{ if (e.Parameter is CalendarPageNavigationArgs args)
if (args.RequestDefaultNavigation) {
{ if (args.RequestDefaultNavigation)
// Go today. {
WeakReferenceMessenger.Default.Send(new LoadCalendarMessage(DateTime.Now.Date, CalendarInitInitiative.App)); // Go today.
} WeakReferenceMessenger.Default.Send(new LoadCalendarMessage(DateTime.Now.Date, CalendarInitInitiative.App));
else }
{ else
// Go specified date. {
WeakReferenceMessenger.Default.Send(new LoadCalendarMessage(args.NavigationDate, CalendarInitInitiative.User)); // Go specified date.
} WeakReferenceMessenger.Default.Send(new LoadCalendarMessage(args.NavigationDate, CalendarInitInitiative.User));
} }
} }
}
private void CellSelected(object sender, TimelineCellSelectedArgs e)
{ private void CellSelected(object sender, TimelineCellSelectedArgs e)
// Dismiss event details if exists and cancel the selection. {
// This is to prevent the event details from being displayed when the user clicks somewhere else. // Dismiss event details if exists and cancel the selection.
// This is to prevent the event details from being displayed when the user clicks somewhere else.
if (EventDetailsPopup.IsOpen)
{ if (EventDetailsPopup.IsOpen)
CalendarControl.UnselectActiveTimelineCell(); {
ViewModel.DisplayDetailsCalendarItemViewModel = null; CalendarControl.UnselectActiveTimelineCell();
ViewModel.DisplayDetailsCalendarItemViewModel = null;
return;
} return;
}
ViewModel.SelectedQuickEventDate = e.ClickedDate;
ViewModel.SelectedQuickEventDate = e.ClickedDate;
TeachingTipPositionerGrid.Width = e.CellSize.Width;
TeachingTipPositionerGrid.Height = e.CellSize.Height; TeachingTipPositionerGrid.Width = e.CellSize.Width;
TeachingTipPositionerGrid.Height = e.CellSize.Height;
Canvas.SetLeft(TeachingTipPositionerGrid, e.PositionerPoint.X);
Canvas.SetTop(TeachingTipPositionerGrid, e.PositionerPoint.Y); Canvas.SetLeft(TeachingTipPositionerGrid, e.PositionerPoint.X);
Canvas.SetTop(TeachingTipPositionerGrid, e.PositionerPoint.Y);
// Adjust the start and end time in the flyout.
var startTime = ViewModel.SelectedQuickEventDate.Value.TimeOfDay; // Adjust the start and end time in the flyout.
var endTime = startTime.Add(TimeSpan.FromMinutes(30)); var startTime = ViewModel.SelectedQuickEventDate.Value.TimeOfDay;
var endTime = startTime.Add(TimeSpan.FromMinutes(30));
ViewModel.SelectQuickEventTimeRange(startTime, endTime);
ViewModel.SelectQuickEventTimeRange(startTime, endTime);
QuickEventPopupDialog.IsOpen = true;
} QuickEventPopupDialog.IsOpen = true;
}
private void CellUnselected(object sender, TimelineCellUnselectedArgs e)
{ private void CellUnselected(object sender, TimelineCellUnselectedArgs e)
QuickEventPopupDialog.IsOpen = false; {
} QuickEventPopupDialog.IsOpen = false;
}
private void QuickEventAccountSelectorSelectionChanged(object sender, SelectionChangedEventArgs e)
{ private void QuickEventAccountSelectorSelectionChanged(object sender, SelectionChangedEventArgs e)
QuickEventAccountSelectorFlyout.Hide(); {
} QuickEventAccountSelectorFlyout.Hide();
}
private void QuickEventPopupClosed(object sender, object e)
{ private void QuickEventPopupClosed(object sender, object e)
// Reset the timeline selection when the tip is closed. {
CalendarControl.ResetTimelineSelection(); // Reset the timeline selection when the tip is closed.
} CalendarControl.ResetTimelineSelection();
}
private void PopupPlacementChanged(object sender, object e)
{ private void PopupPlacementChanged(object sender, object e)
if (sender is Popup senderPopup) {
{ if (sender is Popup senderPopup)
// When the quick event Popup is positioned for different calendar types, {
// we must adjust the offset to make sure the tip is not hidden and has nice // When the quick event Popup is positioned for different calendar types,
// spacing from the cell. // we must adjust the offset to make sure the tip is not hidden and has nice
// spacing from the cell.
switch (senderPopup.ActualPlacement)
{ switch (senderPopup.ActualPlacement)
case PopupPlacementMode.Top: {
senderPopup.VerticalOffset = PopupDialogOffset * -1; case PopupPlacementMode.Top:
break; senderPopup.VerticalOffset = PopupDialogOffset * -1;
case PopupPlacementMode.Bottom: break;
senderPopup.VerticalOffset = PopupDialogOffset; case PopupPlacementMode.Bottom:
break; senderPopup.VerticalOffset = PopupDialogOffset;
case PopupPlacementMode.Left: break;
senderPopup.HorizontalOffset = PopupDialogOffset * -1; case PopupPlacementMode.Left:
break; senderPopup.HorizontalOffset = PopupDialogOffset * -1;
case PopupPlacementMode.Right: break;
senderPopup.HorizontalOffset = PopupDialogOffset; case PopupPlacementMode.Right:
break; senderPopup.HorizontalOffset = PopupDialogOffset;
default: break;
break; default:
} break;
} }
}
}
}
private void StartTimeDurationSubmitted(ComboBox sender, ComboBoxTextSubmittedEventArgs args)
=> ViewModel.SelectedStartTimeString = args.Text; private void StartTimeDurationSubmitted(ComboBox sender, ComboBoxTextSubmittedEventArgs args)
=> ViewModel.SelectedStartTimeString = args.Text;
private void EndTimeDurationSubmitted(ComboBox sender, ComboBoxTextSubmittedEventArgs args)
=> ViewModel.SelectedEndTimeString = args.Text; private void EndTimeDurationSubmitted(ComboBox sender, ComboBoxTextSubmittedEventArgs args)
=> ViewModel.SelectedEndTimeString = args.Text;
private void EventDetailsPopupClosed(object sender, object e)
{ private void EventDetailsPopupClosed(object sender, object e)
ViewModel.DisplayDetailsCalendarItemViewModel = null; {
} ViewModel.DisplayDetailsCalendarItemViewModel = null;
}
private void CalendarScrolling(object sender, EventArgs e)
{ private void CalendarScrolling(object sender, EventArgs e)
// In case of scrolling, we must dismiss the event details dialog. {
ViewModel.DisplayDetailsCalendarItemViewModel = null; // In case of scrolling, we must dismiss the event details dialog.
} ViewModel.DisplayDetailsCalendarItemViewModel = null;
} }
} }

View File

@@ -1,13 +1,12 @@
using Wino.Calendar.Views.Abstract; using Wino.Calendar.Views.Abstract;
namespace Wino.Calendar.Views namespace Wino.Calendar.Views;
public sealed partial class EventDetailsPage : EventDetailsPageAbstract
{ {
public sealed partial class EventDetailsPage : EventDetailsPageAbstract public EventDetailsPage()
{ {
public EventDetailsPage() this.InitializeComponent();
{
this.InitializeComponent();
}
} }
} }

View File

@@ -20,7 +20,7 @@
<controls:SettingsCard.HeaderIcon> <controls:SettingsCard.HeaderIcon>
<PathIcon Data="F1 M 10 0.625 C 10 0.45573 10.061849 0.309246 10.185547 0.185547 C 10.309244 0.06185 10.455729 0 10.625 0 L 15.625 0 C 15.79427 0 15.940754 0.06185 16.064453 0.185547 C 16.18815 0.309246 16.25 0.45573 16.25 0.625 C 16.25 0.794271 16.18815 0.940756 16.064453 1.064453 C 15.940754 1.188152 15.79427 1.25 15.625 1.25 L 13.75 1.25 L 13.75 18.75 L 15.625 18.75 C 15.79427 18.75 15.940754 18.81185 16.064453 18.935547 C 16.18815 19.059244 16.25 19.205729 16.25 19.375 C 16.25 19.544271 16.18815 19.690756 16.064453 19.814453 C 15.940754 19.93815 15.79427 20 15.625 20 L 10.625 20 C 10.455729 20 10.309244 19.93815 10.185547 19.814453 C 10.061849 19.690756 10 19.544271 10 19.375 C 10 19.205729 10.061849 19.059244 10.185547 18.935547 C 10.309244 18.81185 10.455729 18.75 10.625 18.75 L 12.5 18.75 L 12.5 1.25 L 10.625 1.25 C 10.455729 1.25 10.309244 1.188152 10.185547 1.064453 C 10.061849 0.940756 10 0.794271 10 0.625 Z M 0 6.25 C 0 5.735678 0.097656 5.250651 0.292969 4.794922 C 0.488281 4.339193 0.756836 3.94043 1.098633 3.598633 C 1.44043 3.256836 1.837565 2.988281 2.290039 2.792969 C 2.742513 2.597656 3.229167 2.5 3.75 2.5 L 11.25 2.5 L 11.25 3.75 L 3.75 3.75 C 3.404948 3.75 3.081055 3.815105 2.77832 3.945312 C 2.475586 4.075521 2.210286 4.254558 1.982422 4.482422 C 1.754557 4.710287 1.575521 4.975587 1.445312 5.27832 C 1.315104 5.581056 1.25 5.904949 1.25 6.25 L 1.25 13.75 C 1.25 14.095053 1.315104 14.418945 1.445312 14.72168 C 1.575521 15.024414 1.754557 15.289714 1.982422 15.517578 C 2.210286 15.745443 2.475586 15.924479 2.77832 16.054688 C 3.081055 16.184896 3.404948 16.25 3.75 16.25 L 11.25 16.25 L 11.25 17.5 L 3.75 17.5 C 3.229167 17.5 2.742513 17.402344 2.290039 17.207031 C 1.837565 17.011719 1.44043 16.743164 1.098633 16.401367 C 0.756836 16.05957 0.488281 15.662436 0.292969 15.209961 C 0.097656 14.757487 0 14.270834 0 13.75 Z M 15 3.75 L 15 2.5 L 16.25 2.5 C 16.764322 2.5 17.249348 2.597656 17.705078 2.792969 C 18.160807 2.988281 18.55957 3.256836 18.901367 3.598633 C 19.243164 3.94043 19.511719 4.339193 19.707031 4.794922 C 19.902344 5.250651 20 5.735678 20 6.25 L 20 13.75 C 20 14.270834 19.902344 14.757487 19.707031 15.209961 C 19.511719 15.662436 19.243164 16.05957 18.901367 16.401367 C 18.55957 16.743164 18.160807 17.011719 17.705078 17.207031 C 17.249348 17.402344 16.764322 17.5 16.25 17.5 L 15 17.5 L 15 16.25 L 16.25 16.25 C 16.595051 16.25 16.918945 16.184896 17.22168 16.054688 C 17.524414 15.924479 17.789713 15.745443 18.017578 15.517578 C 18.245441 15.289714 18.424479 15.024414 18.554688 14.72168 C 18.684895 14.418945 18.75 14.095053 18.75 13.75 L 18.75 6.25 C 18.75 5.904949 18.684895 5.581056 18.554688 5.27832 C 18.424479 4.975587 18.245441 4.710287 18.017578 4.482422 C 17.789713 4.254558 17.524414 4.075521 17.22168 3.945312 C 16.918945 3.815105 16.595051 3.75 16.25 3.75 Z M 7.441406 5.361328 C 7.389323 5.250651 7.312825 5.162761 7.211914 5.097656 C 7.111002 5.032553 6.998697 5.000001 6.875 5 C 6.751302 5.000001 6.638997 5.032553 6.538086 5.097656 C 6.437174 5.162761 6.360677 5.250651 6.308594 5.361328 L 2.871094 12.861328 C 2.799479 13.017578 2.792969 13.177084 2.851562 13.339844 C 2.910156 13.502604 3.017578 13.619792 3.173828 13.691406 C 3.330078 13.763021 3.489583 13.769531 3.652344 13.710938 C 3.815104 13.652344 3.932292 13.544922 4.003906 13.388672 L 4.84375 11.5625 L 8.896484 11.5625 L 8.90625 11.5625 L 9.746094 13.388672 C 9.817708 13.544922 9.934896 13.652344 10.097656 13.710938 C 10.260416 13.769531 10.419922 13.763021 10.576172 13.691406 C 10.732422 13.619792 10.839844 13.502604 10.898438 13.339844 C 10.957031 13.177084 10.950521 13.017578 10.878906 12.861328 Z M 5.410156 10.3125 L 6.875 7.128906 L 8.339844 10.3125 Z " /> <PathIcon Data="F1 M 10 0.625 C 10 0.45573 10.061849 0.309246 10.185547 0.185547 C 10.309244 0.06185 10.455729 0 10.625 0 L 15.625 0 C 15.79427 0 15.940754 0.06185 16.064453 0.185547 C 16.18815 0.309246 16.25 0.45573 16.25 0.625 C 16.25 0.794271 16.18815 0.940756 16.064453 1.064453 C 15.940754 1.188152 15.79427 1.25 15.625 1.25 L 13.75 1.25 L 13.75 18.75 L 15.625 18.75 C 15.79427 18.75 15.940754 18.81185 16.064453 18.935547 C 16.18815 19.059244 16.25 19.205729 16.25 19.375 C 16.25 19.544271 16.18815 19.690756 16.064453 19.814453 C 15.940754 19.93815 15.79427 20 15.625 20 L 10.625 20 C 10.455729 20 10.309244 19.93815 10.185547 19.814453 C 10.061849 19.690756 10 19.544271 10 19.375 C 10 19.205729 10.061849 19.059244 10.185547 18.935547 C 10.309244 18.81185 10.455729 18.75 10.625 18.75 L 12.5 18.75 L 12.5 1.25 L 10.625 1.25 C 10.455729 1.25 10.309244 1.188152 10.185547 1.064453 C 10.061849 0.940756 10 0.794271 10 0.625 Z M 0 6.25 C 0 5.735678 0.097656 5.250651 0.292969 4.794922 C 0.488281 4.339193 0.756836 3.94043 1.098633 3.598633 C 1.44043 3.256836 1.837565 2.988281 2.290039 2.792969 C 2.742513 2.597656 3.229167 2.5 3.75 2.5 L 11.25 2.5 L 11.25 3.75 L 3.75 3.75 C 3.404948 3.75 3.081055 3.815105 2.77832 3.945312 C 2.475586 4.075521 2.210286 4.254558 1.982422 4.482422 C 1.754557 4.710287 1.575521 4.975587 1.445312 5.27832 C 1.315104 5.581056 1.25 5.904949 1.25 6.25 L 1.25 13.75 C 1.25 14.095053 1.315104 14.418945 1.445312 14.72168 C 1.575521 15.024414 1.754557 15.289714 1.982422 15.517578 C 2.210286 15.745443 2.475586 15.924479 2.77832 16.054688 C 3.081055 16.184896 3.404948 16.25 3.75 16.25 L 11.25 16.25 L 11.25 17.5 L 3.75 17.5 C 3.229167 17.5 2.742513 17.402344 2.290039 17.207031 C 1.837565 17.011719 1.44043 16.743164 1.098633 16.401367 C 0.756836 16.05957 0.488281 15.662436 0.292969 15.209961 C 0.097656 14.757487 0 14.270834 0 13.75 Z M 15 3.75 L 15 2.5 L 16.25 2.5 C 16.764322 2.5 17.249348 2.597656 17.705078 2.792969 C 18.160807 2.988281 18.55957 3.256836 18.901367 3.598633 C 19.243164 3.94043 19.511719 4.339193 19.707031 4.794922 C 19.902344 5.250651 20 5.735678 20 6.25 L 20 13.75 C 20 14.270834 19.902344 14.757487 19.707031 15.209961 C 19.511719 15.662436 19.243164 16.05957 18.901367 16.401367 C 18.55957 16.743164 18.160807 17.011719 17.705078 17.207031 C 17.249348 17.402344 16.764322 17.5 16.25 17.5 L 15 17.5 L 15 16.25 L 16.25 16.25 C 16.595051 16.25 16.918945 16.184896 17.22168 16.054688 C 17.524414 15.924479 17.789713 15.745443 18.017578 15.517578 C 18.245441 15.289714 18.424479 15.024414 18.554688 14.72168 C 18.684895 14.418945 18.75 14.095053 18.75 13.75 L 18.75 6.25 C 18.75 5.904949 18.684895 5.581056 18.554688 5.27832 C 18.424479 4.975587 18.245441 4.710287 18.017578 4.482422 C 17.789713 4.254558 17.524414 4.075521 17.22168 3.945312 C 16.918945 3.815105 16.595051 3.75 16.25 3.75 Z M 7.441406 5.361328 C 7.389323 5.250651 7.312825 5.162761 7.211914 5.097656 C 7.111002 5.032553 6.998697 5.000001 6.875 5 C 6.751302 5.000001 6.638997 5.032553 6.538086 5.097656 C 6.437174 5.162761 6.360677 5.250651 6.308594 5.361328 L 2.871094 12.861328 C 2.799479 13.017578 2.792969 13.177084 2.851562 13.339844 C 2.910156 13.502604 3.017578 13.619792 3.173828 13.691406 C 3.330078 13.763021 3.489583 13.769531 3.652344 13.710938 C 3.815104 13.652344 3.932292 13.544922 4.003906 13.388672 L 4.84375 11.5625 L 8.896484 11.5625 L 8.90625 11.5625 L 9.746094 13.388672 C 9.817708 13.544922 9.934896 13.652344 10.097656 13.710938 C 10.260416 13.769531 10.419922 13.763021 10.576172 13.691406 C 10.732422 13.619792 10.839844 13.502604 10.898438 13.339844 C 10.957031 13.177084 10.950521 13.017578 10.878906 12.861328 Z M 5.410156 10.3125 L 6.875 7.128906 L 8.339844 10.3125 Z " />
</controls:SettingsCard.HeaderIcon> </controls:SettingsCard.HeaderIcon>
<Button Command="{x:Bind ViewModel.RenameAccountCommand}" Content="{x:Bind domain:Translator.FolderOperation_Rename}" /> <Button Command="{x:Bind ViewModel.EditAccountDetailsCommand}" Content="{x:Bind domain:Translator.FolderOperation_Rename}" />
</controls:SettingsCard> </controls:SettingsCard>
<!-- TODO --> <!-- TODO -->

View File

@@ -1,12 +1,11 @@
using Wino.Calendar.Views.Abstract; using Wino.Calendar.Views.Abstract;
namespace Wino.Calendar.Views.Settings namespace Wino.Calendar.Views.Settings;
public sealed partial class AccountDetailsPage : AccountDetailsPageAbstract
{ {
public sealed partial class AccountDetailsPage : AccountDetailsPageAbstract public AccountDetailsPage()
{ {
public AccountDetailsPage() this.InitializeComponent();
{
this.InitializeComponent();
}
} }
} }

View File

@@ -1,13 +1,12 @@
using Wino.Calendar.Views.Abstract; using Wino.Calendar.Views.Abstract;
namespace Wino.Calendar.Views.Settings namespace Wino.Calendar.Views.Settings;
public sealed partial class CalendarSettingsPage : CalendarSettingsPageAbstract
{ {
public sealed partial class CalendarSettingsPage : CalendarSettingsPageAbstract public CalendarSettingsPage()
{ {
public CalendarSettingsPage() InitializeComponent();
{
InitializeComponent();
}
} }
} }

View File

@@ -1,12 +1,11 @@
using Wino.Calendar.Views.Abstract; using Wino.Calendar.Views.Abstract;
namespace Wino.Calendar.Views.Settings namespace Wino.Calendar.Views.Settings;
public sealed partial class PersonalizationPage : PersonalizationPageAbstract
{ {
public sealed partial class PersonalizationPage : PersonalizationPageAbstract public PersonalizationPage()
{ {
public PersonalizationPage() this.InitializeComponent();
{
this.InitializeComponent();
}
} }
} }

View File

@@ -1,184 +1,31 @@
<?xml version="1.0" encoding="utf-8"?> <Project Sdk="Microsoft.NET.Sdk">
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <OutputType>WinExe</OutputType>
<PropertyGroup> <TargetFramework>net9.0-windows10.0.26100.0</TargetFramework>
<LangVersion>8.0</LangVersion> <TargetPlatformMinVersion>10.0.18362.0</TargetPlatformMinVersion>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle> <UseUwp>true</UseUwp>
<!-- UWP WAM Authentication on Xbox needs this. --> <Platforms>x86;x64;arm64</Platforms>
<UseDotNetNativeSharedAssemblyFrameworkPackage>false</UseDotNetNativeSharedAssemblyFrameworkPackage> <RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
<PackageCertificateThumbprint> <DefaultLanguage>en-US</DefaultLanguage>
</PackageCertificateThumbprint> <!--<PublishAot>true</PublishAot>-->
<PackageCertificateKeyFile>Wino.Mail_TemporaryKey.pfx</PackageCertificateKeyFile> <PublishProfile>win-$(Platform).pubxml</PublishProfile>
<GenerateAppInstallerFile>False</GenerateAppInstallerFile> <DisableRuntimeMarshalling>true</DisableRuntimeMarshalling>
<AppxPackageSigningTimestampDigestAlgorithm>SHA256</AppxPackageSigningTimestampDigestAlgorithm> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<AppxAutoIncrementPackageRevision>True</AppxAutoIncrementPackageRevision> <GenerateAppInstallerFile>True</GenerateAppInstallerFile>
<AppxSymbolPackageEnabled>False</AppxSymbolPackageEnabled> <AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>
<GenerateTestArtifacts>True</GenerateTestArtifacts> <AppxPackageSigningTimestampDigestAlgorithm>SHA256</AppxPackageSigningTimestampDigestAlgorithm>
<AppxBundle>Always</AppxBundle> </PropertyGroup>
<AppxBundlePlatforms>x64</AppxBundlePlatforms>
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks> <ItemGroup>
</PropertyGroup> <Compile Remove="BundleArtifacts\**" />
<PropertyGroup> <EmbeddedResource Remove="BundleArtifacts\**" />
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <None Remove="BundleArtifacts\**" />
<Platform Condition=" '$(Platform)' == '' ">x86</Platform> <Page Remove="BundleArtifacts\**" />
<ProjectGuid>{600F4979-DB7E-409D-B7DA-B60BE4C55C35}</ProjectGuid> </ItemGroup>
<OutputType>AppContainerExe</OutputType> <ItemGroup>
<AppDesignerFolder>Properties</AppDesignerFolder> <PRIResource Remove="BundleArtifacts\**" />
<RootNamespace>Wino.Calendar</RootNamespace> </ItemGroup>
<AssemblyName>Wino.Calendar</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.22621.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WindowsXamlEnableOverview>true</WindowsXamlEnableOverview>
<AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>
<GenerateTemporaryStoreCertificate>True</GenerateTemporaryStoreCertificate>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\ARM64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>ARM64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM64'">
<OutputPath>bin\ARM64\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>ARM64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<!-- .NET Native Shit -->
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
<UseDotNetNativeSharedAssemblyFrameworkPackage>false</UseDotNetNativeSharedAssemblyFrameworkPackage>
<Use64BitCompiler>true</Use64BitCompiler>
<OutOfProcPDB>true</OutOfProcPDB>
</PropertyGroup>
<ItemGroup>
<Compile Include="Activation\DefaultActivationHandler.cs" />
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
</Compile>
<Compile Include="Args\TimelineCellSelectedArgs.cs" />
<Compile Include="Args\TimelineCellUnselectedArgs.cs" />
<Compile Include="Controls\CalendarItemCommandBarFlyout.cs" />
<Compile Include="Controls\CalendarItemControl.xaml.cs">
<DependentUpon>CalendarItemControl.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\CustomCalendarFlipView.cs" />
<Compile Include="Controls\DayColumnControl.cs" />
<Compile Include="Controls\DayHeaderControl.cs" />
<Compile Include="Controls\WinoCalendarControl.cs" />
<Compile Include="Controls\WinoCalendarFlipView.cs" />
<Compile Include="Controls\WinoCalendarPanel.cs" />
<Compile Include="Controls\WinoCalendarTypeSelectorControl.cs" />
<Compile Include="Controls\WinoCalendarView.cs" />
<Compile Include="Controls\WinoDayTimelineCanvas.cs" />
<Compile Include="Helpers\CalendarXamlHelpers.cs" />
<Compile Include="MainPage.xaml.cs">
<DependentUpon>MainPage.xaml</DependentUpon>
</Compile>
<Compile Include="Models\CalendarItemMeasurement.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Selectors\CustomAreaCalendarItemSelector.cs" />
<Compile Include="Selectors\WinoCalendarItemTemplateSelector.cs" />
<Compile Include="Services\AccountCalendarStateService.cs" />
<Compile Include="Services\CalendarAuthenticatorConfig.cs" />
<Compile Include="Services\DialogService.cs" />
<Compile Include="Services\NavigationService.cs" />
<Compile Include="Services\ProviderService.cs" />
<Compile Include="Services\SettingsBuilderService.cs" />
<Compile Include="Styles\WinoCalendarResources.xaml.cs" />
<Compile Include="Views\Abstract\AccountDetailsPageAbstract.cs" />
<Compile Include="Views\Abstract\AccountManagementPageAbstract.cs" />
<Compile Include="Views\Abstract\AppShellAbstract.cs" />
<Compile Include="Views\Abstract\CalendarPageAbstract.cs" />
<Compile Include="Views\Abstract\CalendarSettingsPageAbstract.cs" />
<Compile Include="Views\Abstract\EventDetailsPageAbstract.cs" />
<Compile Include="Views\Abstract\PersonalizationPageAbstract.cs" />
<Compile Include="Views\Account\AccountManagementPage.xaml.cs">
<DependentUpon>AccountManagementPage.xaml</DependentUpon>
</Compile>
<Compile Include="Views\AppShell.xaml.cs">
<DependentUpon>AppShell.xaml</DependentUpon>
</Compile>
<Compile Include="Views\CalendarPage.xaml.cs">
<DependentUpon>CalendarPage.xaml</DependentUpon>
</Compile>
<Compile Include="Views\EventDetailsPage.xaml.cs">
<DependentUpon>EventDetailsPage.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Settings\AccountDetailsPage.xaml.cs">
<DependentUpon>AccountDetailsPage.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Settings\CalendarSettingsPage.xaml.cs">
<DependentUpon>CalendarSettingsPage.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Settings\PersonalizationPage.xaml.cs">
<DependentUpon>PersonalizationPage.xaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
</ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Package.StoreAssociation.xml" /> <None Include="Package.StoreAssociation.xml" />
<Content Include="Assets\LargeTile.scale-100.png" /> <Content Include="Assets\LargeTile.scale-100.png" />
@@ -226,7 +73,6 @@
<Content Include="Assets\Wide310x150Logo.scale-125.png" /> <Content Include="Assets\Wide310x150Logo.scale-125.png" />
<Content Include="Assets\Wide310x150Logo.scale-150.png" /> <Content Include="Assets\Wide310x150Logo.scale-150.png" />
<Content Include="Assets\Wide310x150Logo.scale-400.png" /> <Content Include="Assets\Wide310x150Logo.scale-400.png" />
<Content Include="Properties\Default.rd.xml" />
<Content Include="Assets\LockScreenLogo.scale-200.png" /> <Content Include="Assets\LockScreenLogo.scale-200.png" />
<Content Include="Assets\SplashScreen.scale-200.png" /> <Content Include="Assets\SplashScreen.scale-200.png" />
<Content Include="Assets\Square150x150Logo.scale-200.png" /> <Content Include="Assets\Square150x150Logo.scale-200.png" />
@@ -235,120 +81,18 @@
<Content Include="Assets\Wide310x150Logo.scale-200.png" /> <Content Include="Assets\Wide310x150Logo.scale-200.png" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ApplicationDefinition Include="App.xaml"> <PackageReference Include="CommunityToolkit.Uwp.Controls.Primitives" />
<Generator>MSBuild:Compile</Generator> <PackageReference Include="Microsoft.Identity.Client" />
<SubType>Designer</SubType> <PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform" />
</ApplicationDefinition> <PackageReference Include="Win2D.uwp" />
<Page Include="Controls\CalendarItemControl.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="MainPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Styles\CalendarThemeResources.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Styles\DayHeaderControl.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Styles\WinoCalendarResources.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Styles\WinoCalendarTypeSelectorControl.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Styles\WinoCalendarView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Styles\WinoDayTimelineCanvas.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\Account\AccountManagementPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\AppShell.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\CalendarPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\EventDetailsPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Settings\AccountDetailsPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Settings\CalendarSettingsPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Settings\PersonalizationPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="CommunityToolkit.Uwp.Controls.Primitives"> <ProjectReference Include="..\Wino.Authentication\Wino.Authentication.csproj" />
<Version>8.1.240916</Version> <ProjectReference Include="..\Wino.Calendar.ViewModels\Wino.Calendar.ViewModels.csproj" />
</PackageReference> <ProjectReference Include="..\Wino.Core.Domain\Wino.Core.Domain.csproj" />
<PackageReference Include="Microsoft.Identity.Client"> <ProjectReference Include="..\Wino.Core.UWP\Wino.Core.UWP.csproj" />
<Version>4.66.2</Version> <ProjectReference Include="..\Wino.Core.ViewModels\Wino.Core.ViewModels.csproj" />
</PackageReference> <ProjectReference Include="..\Wino.Messages\Wino.Messaging.csproj" />
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform"> <ProjectReference Include="..\Wino.Services\Wino.Services.csproj" />
<Version>6.2.14</Version>
</PackageReference>
<PackageReference Include="Win2D.uwp">
<Version>1.28.1</Version>
</PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Wino.Calendar.ViewModels\Wino.Calendar.ViewModels.csproj">
<Project>{039affa8-c1cc-4e3b-8a31-6814d7557f74}</Project>
<Name>Wino.Calendar.ViewModels</Name>
</ProjectReference>
<ProjectReference Include="..\Wino.Core.Domain\Wino.Core.Domain.csproj">
<Project>{cf3312e5-5da0-4867-9945-49ea7598af1f}</Project>
<Name>Wino.Core.Domain</Name>
</ProjectReference>
<ProjectReference Include="..\Wino.Core.UWP\Wino.Core.UWP.csproj">
<Project>{395f19ba-1e42-495c-9db5-1a6f537fccb8}</Project>
<Name>Wino.Core.UWP</Name>
</ProjectReference>
<ProjectReference Include="..\Wino.Core.ViewModels\Wino.Core.ViewModels.csproj">
<Project>{53723ae8-7e7e-4d54-adab-0a6033255cc8}</Project>
<Name>Wino.Core.ViewModels</Name>
</ProjectReference>
<ProjectReference Include="..\Wino.Messages\Wino.Messaging.csproj">
<Project>{0c307d7e-256f-448c-8265-5622a812fbcc}</Project>
<Name>Wino.Messaging</Name>
</ProjectReference>
<ProjectReference Include="..\Wino.Services\Wino.Services.csproj">
<Project>{bba49030-7277-48cf-b2fe-3d01cb6b6c81}</Project>
<Name>Wino.Services</Name>
</ProjectReference>
</ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project> </Project>

View File

@@ -0,0 +1,14 @@
using System;
using SQLite;
namespace Wino.Core.Domain.Entities.Shared;
public class Thumbnail
{
[PrimaryKey]
public string Domain { get; set; }
public string Gravatar { get; set; }
public string Favicon { get; set; }
public DateTime LastUpdated { get; set; }
}

View File

@@ -25,7 +25,7 @@ public enum WinoPage
AppPreferencesPage, AppPreferencesPage,
SettingOptionsPage, SettingOptionsPage,
AliasManagementPage, AliasManagementPage,
EditAccountDetailsPage,
// Calendar // Calendar
CalendarPage, CalendarPage,
CalendarSettingsPage, CalendarSettingsPage,

View File

@@ -20,7 +20,7 @@ public class ImapClientPoolException : Exception
ProtocolLog = protocolLog; ProtocolLog = protocolLog;
} }
public ImapClientPoolException(Exception innerException, string protocolLog) : base(Translator.Exception_ImapClientPoolFailed, innerException) public ImapClientPoolException(Exception innerException, string protocolLog) : base(innerException.Message, innerException)
{ {
ProtocolLog = protocolLog; ProtocolLog = protocolLog;
} }

View File

@@ -62,15 +62,6 @@ public interface IAccountService
/// <param name="accountId">Account id to remove from</param> /// <param name="accountId">Account id to remove from</param>
Task ClearAccountAttentionAsync(Guid accountId); Task ClearAccountAttentionAsync(Guid accountId);
/// <summary>
/// Updates the account synchronization identifier.
/// For example: Gmail uses this identifier to keep track of the last synchronization.
/// Update is ignored for Gmail if the new identifier is older than the current one.
/// </summary>
/// <param name="newIdentifier">Identifier to update</param>
/// <returns>Current account synchronization modifier.</returns>
Task<string> UpdateSynchronizationIdentifierAsync(Guid accountId, string newIdentifier);
/// <summary> /// <summary>
/// Renames the merged inbox with the given id. /// Renames the merged inbox with the given id.
/// </summary> /// </summary>
@@ -164,4 +155,20 @@ public interface IAccountService
/// <param name="accountId">Account id.</param> /// <param name="accountId">Account id.</param>
/// <param name="AccountCacheResetReason">Reason for the cache reset.</param> /// <param name="AccountCacheResetReason">Reason for the cache reset.</param>
Task DeleteAccountMailCacheAsync(Guid accountId, AccountCacheResetReason accountCacheResetReason); Task DeleteAccountMailCacheAsync(Guid accountId, AccountCacheResetReason accountCacheResetReason);
/// <summary>
/// Updates the synchronization identifier for a specific account asynchronously.
/// </summary>
/// <param name="accountId">Identifies the account for which the synchronization identifier is being updated.</param>
/// <param name="syncIdentifier">Represents the new synchronization identifier to be set for the specified account.</param>
Task<string> UpdateSyncIdentifierRawAsync(Guid accountId, string syncIdentifier);
/// <summary>
/// Gets whether the notifications are enabled for the given account id.
/// </summary>
/// <param name="accountId">Account id.</param>
/// <returns>Whether the notifications should be created after sync or not.</returns>
Task<bool> IsNotificationsEnabled(Guid accountId);
Task UpdateAccountCustomServerInformationAsync(CustomServerInformation customServerInformation);
} }

View File

@@ -27,5 +27,5 @@ public interface IApplicationConfiguration
/// <summary> /// <summary>
/// Application insights instrumentation key. /// Application insights instrumentation key.
/// </summary> /// </summary>
string ApplicationInsightsInstrumentationKey { get; } string SentryDNS { get; }
} }

View File

@@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Wino.Core.Domain.Entities.Shared;
using Wino.Core.Domain.Enums; using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Models.Accounts; using Wino.Core.Domain.Models.Accounts;
using Wino.Core.Domain.Models.Common; using Wino.Core.Domain.Models.Common;
@@ -17,7 +16,6 @@ public interface IDialogServiceBase
void InfoBarMessage(string title, string message, InfoBarMessageType messageType); void InfoBarMessage(string title, string message, InfoBarMessageType messageType);
void InfoBarMessage(string title, string message, InfoBarMessageType messageType, string actionButtonText, Action action); void InfoBarMessage(string title, string message, InfoBarMessageType messageType, string actionButtonText, Action action);
void ShowNotSupportedMessage(); void ShowNotSupportedMessage();
Task<MailAccount> ShowEditAccountDialogAsync(MailAccount account);
Task<string> ShowTextInputDialogAsync(string currentInput, string dialogTitle, string dialogDescription, string primaryButtonText); Task<string> ShowTextInputDialogAsync(string currentInput, string dialogTitle, string dialogDescription, string primaryButtonText);
Task<bool> ShowWinoCustomMessageDialogAsync(string title, Task<bool> ShowWinoCustomMessageDialogAsync(string title,
string description, string description,

View File

@@ -13,4 +13,5 @@ public interface IImapSynchronizer
Task<List<NewMailItemPackage>> CreateNewMailPackagesAsync(ImapMessageCreationPackage message, MailItemFolder assignedFolder, CancellationToken cancellationToken = default); Task<List<NewMailItemPackage>> CreateNewMailPackagesAsync(ImapMessageCreationPackage message, MailItemFolder assignedFolder, CancellationToken cancellationToken = default);
Task StartIdleClientAsync(); Task StartIdleClientAsync();
Task StopIdleClientAsync(); Task StopIdleClientAsync();
Task PreWarmClientPoolAsync();
} }

View File

@@ -22,4 +22,9 @@ public interface INotificationBuilder
/// Creates test notification for test purposes. /// Creates test notification for test purposes.
/// </summary> /// </summary>
Task CreateTestNotificationAsync(string title, string message); Task CreateTestNotificationAsync(string title, string message);
/// <summary>
/// Removes the toast notification for a specific mail by unique id.
/// </summary>
void RemoveNotification(Guid mailUniqueId);
} }

View File

@@ -1,11 +1,12 @@
using System; using System;
using System.ComponentModel;
using Wino.Core.Domain.Enums; using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Models.Calendar; using Wino.Core.Domain.Models.Calendar;
using Wino.Core.Domain.Models.Reader; using Wino.Core.Domain.Models.Reader;
namespace Wino.Core.Domain.Interfaces; namespace Wino.Core.Domain.Interfaces;
public interface IPreferencesService public interface IPreferencesService: INotifyPropertyChanged
{ {
/// <summary> /// <summary>
/// When any of the preferences are changed. /// When any of the preferences are changed.
@@ -50,6 +51,12 @@ public interface IPreferencesService
/// Local search will still offer online search at the end of local search results. /// Local search will still offer online search at the end of local search results.
/// </summary> /// </summary>
SearchMode DefaultSearchMode { get; set; } SearchMode DefaultSearchMode { get; set; }
/// <summary>
/// Setting: Interval in minutes for background email synchronization.
/// </summary>
int EmailSyncIntervalMinutes { get; set; }
#endregion #endregion
#region Mail #region Mail
@@ -188,6 +195,21 @@ public interface IPreferencesService
/// </summary> /// </summary>
bool IsMailListActionBarEnabled { get; set; } bool IsMailListActionBarEnabled { get; set; }
/// <summary>
/// Setting: Whether the mail rendering page will show the action labels
/// </summary>
bool IsShowActionLabelsEnabled { get; set; }
/// <summary>
/// Setting: Enable/disable Gravatar for sender avatars.
/// </summary>
bool IsGravatarEnabled { get; set; }
/// <summary>
/// Setting: Enable/disable Favicon for sender avatars.
/// </summary>
bool IsFaviconEnabled { get; set; }
#endregion #endregion
#region Calendar #region Calendar

View File

@@ -14,7 +14,7 @@ public interface IThemeService : IInitializeAsync
Task<List<AppThemeBase>> GetAvailableThemesAsync(); Task<List<AppThemeBase>> GetAvailableThemesAsync();
Task<CustomThemeMetadata> CreateNewCustomThemeAsync(string themeName, string accentColor, byte[] wallpaperData); Task<CustomThemeMetadata> CreateNewCustomThemeAsync(string themeName, string accentColor, byte[] wallpaperData);
Task<List<CustomThemeMetadata>> GetCurrentCustomThemesAsync(); Task<List<CustomThemeMetadata>> GetCurrentCustomThemesAsync();
List<string> GetAvailableAccountColors();
Task ApplyCustomThemeAsync(bool isInitializing); Task ApplyCustomThemeAsync(bool isInitializing);
// Settings // Settings

View File

@@ -0,0 +1,20 @@
using System.Threading.Tasks;
namespace Wino.Core.Domain.Interfaces;
public interface IThumbnailService
{
/// <summary>
/// Clears the thumbnail cache.
/// </summary>
Task ClearCache();
/// <summary>
/// Gets thumbnail
/// </summary>
/// <param name="email">Address for thumbnail</param>
/// <param name="awaitLoad">Force to wait for thumbnail loading.
/// Should be used in non-UI threads or where delay is acceptable
/// </param>
ValueTask<string> GetThumbnailAsync(string email, bool awaitLoad = false);
}

View File

@@ -56,6 +56,12 @@ public partial class AccountMenuItem : MenuItemBase<MailAccount, MenuItemBase<IM
set => SetProperty(Parameter.Base64ProfilePictureData, value, Parameter, (u, n) => u.Base64ProfilePictureData = n); set => SetProperty(Parameter.Base64ProfilePictureData, value, Parameter, (u, n) => u.Base64ProfilePictureData = n);
} }
public string AccountColorHex
{
get => Parameter.AccountColorHex;
set => SetProperty(Parameter.AccountColorHex, value, Parameter, (u, n) => u.AccountColorHex = n);
}
public IEnumerable<MailAccount> HoldingAccounts => new List<MailAccount> { Parameter }; public IEnumerable<MailAccount> HoldingAccounts => new List<MailAccount> { Parameter };
public AccountMenuItem(MailAccount account, IMenuItem parent = null) : base(account, account.Id, parent) public AccountMenuItem(MailAccount account, IMenuItem parent = null) : base(account, account.Id, parent)
@@ -66,9 +72,11 @@ public partial class AccountMenuItem : MenuItemBase<MailAccount, MenuItemBase<IM
public void UpdateAccount(MailAccount account) public void UpdateAccount(MailAccount account)
{ {
Parameter = account; Parameter = account;
AccountName = account.Name;
AttentionReason = account.AttentionReason; OnPropertyChanged(nameof(AccountName));
Base64ProfilePicture = account.Base64ProfilePictureData; OnPropertyChanged(nameof(Base64ProfilePicture));
OnPropertyChanged(nameof(AccountColorHex));
OnPropertyChanged(nameof(IsAttentionRequired));
if (SubMenuItems == null) return; if (SubMenuItems == null) return;

View File

@@ -2,4 +2,4 @@
namespace Wino.Core.Domain.Models.Accounts; namespace Wino.Core.Domain.Models.Accounts;
public record AccountCreationDialogResult(MailProviderType ProviderType, string AccountName, SpecialImapProviderDetails SpecialImapProviderDetails); public record AccountCreationDialogResult(MailProviderType ProviderType, string AccountName, SpecialImapProviderDetails SpecialImapProviderDetails, string AccountColorHex);

View File

@@ -10,4 +10,4 @@ namespace Wino.Core.Domain.Models;
[JsonSerializable(typeof(CustomThemeMetadata))] [JsonSerializable(typeof(CustomThemeMetadata))]
[JsonSerializable(typeof(WebViewMessage))] [JsonSerializable(typeof(WebViewMessage))]
[JsonSerializable(typeof(List<ImageInfo>))] [JsonSerializable(typeof(List<ImageInfo>))]
public partial class DomainModelsJsonContext: JsonSerializerContext; public partial class DomainModelsJsonContext : JsonSerializerContext;

View File

@@ -0,0 +1,706 @@
{
"AccountAlias_Column_Alias": "Псевдоним",
"AccountAlias_Column_IsPrimaryAlias": "Основен",
"AccountAlias_Column_Verified": "Потвърден",
"AccountAlias_Disclaimer_FirstLine": "Wino може да импортира псевдоними само за вашите акаунти в Gmail.",
"AccountAlias_Disclaimer_SecondLine": "Ако искате да използвате псевдоними за акаунта си в Outlook или IMAP, добавете ги сами.",
"AccountCacheReset_Title": "Нулиране на кеша на акаунта",
"AccountCacheReset_Message": "Този акаунт изисква пълна ресинхронизация, за да продължи да работи. Моля, изчакайте, докато Wino ресинхронизира съобщенията ви...",
"AccountContactNameYou": "Вие",
"AccountCreationDialog_Completed": "всичко е готово",
"AccountCreationDialog_FetchingEvents": "Извличане на събитията от календара.",
"AccountCreationDialog_FetchingProfileInformation": "Извличане на данните за профила.",
"AccountCreationDialog_GoogleAuthHelpClipboardText_Row0": "Ако браузърът ви не се е стартирал автоматично, за да завърши удостоверяването:",
"AccountCreationDialog_GoogleAuthHelpClipboardText_Row1": "1) Щракнете върху бутона по-долу, за да копирате адреса за удостоверяване",
"AccountCreationDialog_GoogleAuthHelpClipboardText_Row2": "2) Стартирайте уеб браузъра си (Edge, Chrome, Firefox и др.)",
"AccountCreationDialog_GoogleAuthHelpClipboardText_Row3": "3) Поставете копирания адрес и отидете на уебсайта, за да завършите удостоверяването ръчно.",
"AccountCreationDialog_Initializing": "инициализиране",
"AccountCreationDialog_PreparingFolders": "В момента получаваме информация за папките.",
"AccountCreationDialog_SigninIn": "Информацията за акаунта се запазва.",
"AccountEditDialog_Message": "Име на акаунта",
"AccountEditDialog_Title": "Редактиране на акаунта",
"AccountPickerDialog_Title": "Изберете акаунт",
"AccountSettingsDialog_AccountName": "Име на подателя",
"AccountSettingsDialog_AccountNamePlaceholder": "напр. Иван Иванов",
"AccountDetailsPage_Title": "Информация за акаунта",
"AccountDetailsPage_Description": "Променете името на акаунта в Wino и задайте желаното име на изпращача.",
"AccountDetailsPage_ColorPicker_Title": "Цвят на акаунта",
"AccountDetailsPage_ColorPicker_Description": "Задайте цвят на акаунта, за да оцветите символа му в списъка.",
"AddHyperlink": "Добавяне",
"AppCloseBackgroundSynchronizationWarningTitle": "Синхронизация на заден план",
"AppCloseStartupLaunchDisabledWarningMessageFirstLine": "Приложението не е настроено да се стартира при стартиране на Windows.",
"AppCloseStartupLaunchDisabledWarningMessageSecondLine": "Това ще доведе до пропускане на известия при рестартиране на компютъра.",
"AppCloseStartupLaunchDisabledWarningMessageThirdLine": "Искате ли да отидете на страницата с настройки на приложението, за да я активирате?",
"AppCloseTerminateBehaviorWarningMessageFirstLine": "Прекратявате Wino Mail и поведението му при затваряне на приложението е настроено на „Прекратяване“.",
"AppCloseTerminateBehaviorWarningMessageSecondLine": "Това ще спре всички фонови синхронизации и известия.",
"AppCloseTerminateBehaviorWarningMessageThirdLine": "Искате ли да отидете в Предпочитания за приложението, за да настроите Wino Mail да работи минимизиран или във фонов режим?",
"AutoDiscoveryProgressMessage": "Търсене на настройки на пощата...",
"BasicIMAPSetupDialog_AdvancedConfiguration": "Разширено конфигуриране",
"BasicIMAPSetupDialog_CredentialLocalMessage": "Вашите идентификационни данни се съхраняват само локално на вашия компютър.",
"BasicIMAPSetupDialog_Description": "Някои акаунти изискват допълнителни стъпки за влизане",
"BasicIMAPSetupDialog_DisplayName": "Показвано име",
"BasicIMAPSetupDialog_DisplayNamePlaceholder": "напр. Иван Иванов",
"BasicIMAPSetupDialog_LearnMore": "Научете повече",
"BasicIMAPSetupDialog_MailAddress": "Адрес на имейл",
"BasicIMAPSetupDialog_MailAddressPlaceholder": "ivanivanov@mail.com",
"BasicIMAPSetupDialog_Password": "Парола",
"BasicIMAPSetupDialog_Title": "IMAP акаунт",
"Busy": "Зает",
"Buttons_AddAccount": "Добавяне на акаунт",
"Buttons_AddNewAlias": "Добавяне на нов псевдоним",
"Buttons_Allow": "Позволяване",
"Buttons_ApplyTheme": "Прилагане на темата",
"Buttons_Browse": "Преглед",
"Buttons_Cancel": "Отказ",
"Buttons_Close": "Затваряне",
"Buttons_Copy": "Копиране",
"Buttons_Create": "Създаване",
"Buttons_CreateAccount": "Създаване на акаунт",
"Buttons_Delete": "Изтриване",
"Buttons_Deny": "Отказване",
"Buttons_Discard": "Отхвърляне",
"Buttons_Edit": "Редактиране",
"Buttons_EnableImageRendering": "Активиране",
"Buttons_Multiselect": "Избор на няколко",
"Buttons_No": "Не",
"Buttons_Open": "Отваряне",
"Buttons_Purchase": "Купете",
"Buttons_RateWino": "Оценете Wino",
"Buttons_Reset": "Нулиране",
"Buttons_Save": "Запазване",
"Buttons_SaveConfiguration": "Запазване на конфигурацията",
"Buttons_Send": "Изпращане",
"Buttons_Share": "Споделяне",
"Buttons_SignIn": "Вход",
"Buttons_Sync": "Синхронизиране",
"Buttons_SyncAliases": "Синхронизиране на псевдонимите",
"Buttons_TryAgain": "Нов опит",
"Buttons_Yes": "Да",
"CalendarAllDayEventSummary": "целодневни събития",
"CalendarDisplayOptions_Color": "Цвят",
"CalendarDisplayOptions_Expand": "Разширяване",
"CalendarItem_DetailsPopup_JoinOnline": "Присъединяване онлайн",
"CalendarItem_DetailsPopup_ViewEventButton": "Преглед на събитието",
"CalendarItem_DetailsPopup_ViewSeriesButton": "Преглед на сериите",
"CalendarItemAllDay": "цял ден",
"CategoriesFolderNameOverride": "Категории",
"Center": "Център",
"ClipboardTextCopied_Message": "{0} е копирано в клипборда.",
"ClipboardTextCopied_Title": "Копирано",
"ClipboardTextCopyFailed_Message": "Неуспешно копиране на {0} в клипборда.",
"ComingSoon": "Очаквайте скоро...",
"ComposerAttachmentsDragDropAttach_Message": "Прикачване",
"ComposerAttachmentsDropZone_Message": "Пуснете файловете си тук",
"ComposerFrom": "От: ",
"ComposerImagesDropZone_Message": "Пуснете изображенията си тук",
"ComposerSubject": "Тема: ",
"ComposerTo": "До: ",
"ComposerToPlaceholder": "натиснете Enter, за да въведете адреси",
"CreateAccountAliasDialog_AliasAddress": "Адрес",
"CreateAccountAliasDialog_AliasAddressPlaceholder": "напр. support@mydomain.com",
"CreateAccountAliasDialog_Description": "Уверете се, че вашият изходящ сървър позволява изпращането на имейли от този псевдоним.",
"CreateAccountAliasDialog_ReplyToAddress": "Адрес за отговор",
"CreateAccountAliasDialog_ReplyToAddressPlaceholder": "admin@mydomain.com",
"CreateAccountAliasDialog_Title": "Създаване на псевдоним на акаунта",
"CustomThemeBuilder_AccentColorDescription": "Задайте персонализиран цвят на акцента, ако желаете. Ако не изберете цвят, ще се използва акцентиращият цвят на Windows.",
"CustomThemeBuilder_AccentColorTitle": "Акцентиращ цвят",
"CustomThemeBuilder_PickColor": "Избор",
"CustomThemeBuilder_ThemeNameDescription": "Уникално име за вашата персонализирана тема.",
"CustomThemeBuilder_ThemeNameTitle": "Име на темата",
"CustomThemeBuilder_Title": "Изграждане на персонализирана тема",
"CustomThemeBuilder_WallpaperDescription": "Задаване на персонализиран тапет за Wino",
"CustomThemeBuilder_WallpaperTitle": "Задаване на персонализиран тапет",
"Dialog_DontAskAgain": "Не питайте отново",
"DialogMessage_AccountLimitMessage": "Достигнали сте лимита за създаване на акаунти.\nИскате ли да закупите добавката „Неограничен акаунт“, за да продължите?",
"DialogMessage_AccountLimitTitle": "Достигнат е лимита на акаунтите",
"DialogMessage_AliasCreatedMessage": "Новият псевдоним е създаден успешно.",
"DialogMessage_AliasCreatedTitle": "Създаден е нов псевдоним",
"DialogMessage_AliasExistsMessage": "Този псевдоним вече се използва.",
"DialogMessage_AliasExistsTitle": "Съществуващ псевдоним",
"DialogMessage_AliasNotSelectedMessage": "Трябва да изберете псевдоним, преди да изпратите съобщение.",
"DialogMessage_AliasNotSelectedTitle": "Липсващ псевдоним",
"DialogMessage_CantDeleteRootAliasMessage": "Основният псевдоним не може да бъде изтрит. Това е основната ви самоличност, свързана с настройката на профила ви.",
"DialogMessage_CantDeleteRootAliasTitle": "Не може да се изтрие псевдонимът",
"DialogMessage_CleanupFolderMessage": "Искате ли да изтриете окончателно всички писма в тази папка?",
"DialogMessage_CleanupFolderTitle": "Почистване на папката",
"DialogMessage_ComposerMissingRecipientMessage": "Съобщението няма получател.",
"DialogMessage_ComposerValidationFailedTitle": "Валидирането е неуспешно",
"DialogMessage_CreateLinkedAccountMessage": "Дайте име на тази нова връзка. Акаунтите ще бъдат обединени под това име.",
"DialogMessage_CreateLinkedAccountTitle": "Име на връзката с акаунта",
"DialogMessage_DeleteAccountConfirmationMessage": "Изтриване на {0}?",
"DialogMessage_DeleteAccountConfirmationTitle": "Всички данни, свързани с този акаунт, ще бъдат изтрити от диска за постоянно.",
"DialogMessage_DiscardDraftConfirmationMessage": "Тази чернова ще бъде отхвърлена. Искате ли да продължите?",
"DialogMessage_DiscardDraftConfirmationTitle": "Отхвърляне на черновата",
"DialogMessage_EmptySubjectConfirmation": "Липсваща тема",
"DialogMessage_EmptySubjectConfirmationMessage": "Съобщението няма тема. Искате ли да продължите?",
"DialogMessage_EnableStartupLaunchDeniedMessage": "Можете да активирате автоматично стартиране от Настройки -> Предпочитания за приложението.",
"DialogMessage_EnableStartupLaunchMessage": "Позволете на Wino Mail да се стартира автоматично минимизиран при стартиране на Windows, за да не пропускате никакви известия.\n\nИскате ли да разрешите автоматичното стартиране?",
"DialogMessage_EnableStartupLaunchTitle": "Активиране на автоматичното стартиране",
"DialogMessage_HardDeleteConfirmationMessage": "Окончателно изтриване",
"DialogMessage_HardDeleteConfirmationTitle": "Съобщението/ята ще бъдат изтрити за постоянно. Искате ли да продължите?",
"DialogMessage_InvalidAliasMessage": "Този псевдоним не е валиден. Уверете се, че всички адреси от псевдонима са валидни имейл адреси.",
"DialogMessage_InvalidAliasTitle": "Невалиден псевдоним",
"DialogMessage_NoAccountsForCreateMailMessage": "Нямате акаунти, от които да създадете съобщение.",
"DialogMessage_NoAccountsForCreateMailTitle": "Липсва акаунт",
"DialogMessage_PrintingFailedMessage": "Неуспешно отпечатване на този имейл. Резултат: {0}",
"DialogMessage_PrintingFailedTitle": "Неуспешно",
"DialogMessage_PrintingSuccessMessage": "Имейлът се изпраща към принтера.",
"DialogMessage_PrintingSuccessTitle": "Успешно",
"DialogMessage_RenameFolderMessage": "Въведете ново име за тази папка",
"DialogMessage_RenameFolderTitle": "Преименуване на папката",
"DialogMessage_RenameLinkedAccountsMessage": "Въведете ново име за свързания акаунт",
"DialogMessage_RenameLinkedAccountsTitle": "Преименуване на свързания акаунт",
"DialogMessage_UnlinkAccountsConfirmationMessage": "Тази операция няма да доведе до изтриване на акаунтите ви, а само до прекъсване на връзката към споделените папки. Искате ли да продължите?",
"DialogMessage_UnlinkAccountsConfirmationTitle": "Премахване на връзката между акаунтите",
"DialogMessage_UnsubscribeConfirmationGoToWebsiteConfirmButton": "Към уебсайта",
"DialogMessage_UnsubscribeConfirmationGoToWebsiteMessage": "За да спрете да получавате съобщения от {0}, отидете на техния уебсайт, за да се отпишете.",
"DialogMessage_UnsubscribeConfirmationMailtoMessage": "Искате ли да спрете да получавате съобщения от {0}? Wino ще се откаже от абонамента вместо вас, като изпрати имейл от вашия имейл акаунт до {1}.",
"DialogMessage_UnsubscribeConfirmationOneClickMessage": "Искате ли да спрете да получавате съобщения от {0}?",
"DialogMessage_UnsubscribeConfirmationTitle": "Отписване",
"DiscordChannelDisclaimerMessage": "Wino няма собствен сървър в Discord, но специалният канал 'wino-mail' се хоства на сървъра „Developer Sanctuary“.\nЗа да получавате актуализации за Wino, моля, присъединете се към сървъра Developer Sanctuary и следвайте канала „wino-mail“ в „Community Projects“.\n\nЩе бъдете пренасочени към URL адреса на сървъра, тъй като Discord не поддържа покани за канали.",
"DiscordChannelDisclaimerTitle": "Важна информация за Discord",
"Draft": "Чернова",
"DragMoveToFolderCaption": "Преместване в {0}",
"EditorToolbarOption_Draw": "Рисуване",
"EditorToolbarOption_Format": "Форматиране",
"EditorToolbarOption_Insert": "Вмъкване",
"EditorToolbarOption_None": "Няма",
"EditorToolbarOption_Options": "Опции",
"EditorTooltip_WebViewEditor": "Използване на редактор в уеб изглед",
"ElementTheme_Dark": "Тъмен режим",
"ElementTheme_Default": "Използване на системната настройка",
"ElementTheme_Light": "Светъл режим",
"Emoji": "Емотикони",
"Error_FailedToSetupSystemFolders_Title": "Неуспешна настройка на системните папки",
"Exception_AuthenticationCanceled": "Удостоверяването е отменено",
"Exception_CustomThemeExists": "Тази тема вече съществува.",
"Exception_CustomThemeMissingName": "Трябва да посочите име.",
"Exception_CustomThemeMissingWallpaper": "Трябва да предоставите персонализирано фоново изображение.",
"Exception_FailedToSynchronizeAliases": "Неуспешно синхронизиране на псевдонимите",
"Exception_FailedToSynchronizeFolders": "Неуспешно синхронизиране на папките",
"Exception_FailedToSynchronizeProfileInformation": "Неуспешно синхронизиране на информацията за профила",
"Exception_GoogleAuthCallbackNull": "Callback uri е празенl при активиране.",
"Exception_GoogleAuthCorruptedCode": "Повреден отговор за упълномощаване.",
"Exception_GoogleAuthError": "Грешка при оторизацията на OAuth: {0}",
"Exception_GoogleAuthInvalidResponse": "Получена заявка с невалидно състояние ({0})",
"Exception_GoogleAuthorizationCodeExchangeFailed": "Обменът на код за упълномощаване е неуспешен.",
"Exception_ImapAutoDiscoveryFailed": "Не могат да се намерят настройките на пощенската кутия.",
"Exception_ImapClientPoolFailed": "IMAP Client Pool се провали.",
"Exception_InboxNotAvailable": "Не може да се настроят папките на акаунта.",
"Exception_InvalidSystemFolderConfiguration": "Конфигурацията на системната папка не е валидна. Проверете конфигурацията и опитайте отново.",
"Exception_InvalidMultiAccountMoveTarget": "Не можете да премествате няколко елемента, които принадлежат на различни акаунти, в свързан акаунт.",
"Exception_MailProcessing": "Тази поща все още се обработва. Моля, опитайте отново след няколко секунди.",
"Exception_MissingAlias": "За този акаунт не съществува първичен псевдоним. Създаването на чернова е неуспешно.",
"Exception_NullAssignedAccount": "Присвоеният акаунт е нулев",
"Exception_NullAssignedFolder": "Присвоената папка е нулева",
"Exception_SynchronizerFailureHTTP": "Обработката на отговора е неуспешна с грешка HTTP код {0}",
"Exception_TokenGenerationFailed": "Неуспешно генериране на токен",
"Exception_TokenInfoRetrivalFailed": "Не се получи информация за токена.",
"Exception_UnknowErrorDuringAuthentication": "Възникна неизвестна грешка по време на удостоверяването",
"Exception_UnsupportedAction": "Действието {0} не е внедрено в процесора за обработка на заявки",
"Exception_UnsupportedProvider": "Този доставчик не се поддържа.",
"Exception_UnsupportedSynchronizerOperation": "Тази операция не се поддържа за {0}",
"Exception_UserCancelSystemFolderSetupDialog": "Диалогът за конфигуриране на системната папка е отменен от потребителя.",
"Exception_WinoServerException": "Сървърът на Wino е неуспешен.",
"Files": "Файлове",
"FilteringOption_All": "Всички",
"FilteringOption_Files": "Съдържа файлове",
"FilteringOption_Flagged": "Отбелязани",
"FilteringOption_Unread": "Непрочетени",
"Focused": "На фокус",
"FolderOperation_CreateSubFolder": "Създаване на подпапка",
"FolderOperation_Delete": "Изтриване",
"FolderOperation_DontSync": "Да не се синхронизира тази папка",
"FolderOperation_Empty": "Изпразване на тази папка",
"FolderOperation_MarkAllAsRead": "Маркиране на всички като прочетени",
"FolderOperation_Move": "Преместване",
"FolderOperation_None": "Няма",
"FolderOperation_Pin": "Фиксиране",
"FolderOperation_Rename": "Преименуване",
"FolderOperation_Unpin": "Освобождаване",
"GeneralTitle_Error": "Грешка",
"GeneralTitle_Info": "Информация",
"GeneralTitle_Warning": "Внимание",
"GmailServiceDisabled_Title": "Грешка в Gmail",
"GmailServiceDisabled_Message": "Вашият акаунт в Google Workspace изглежда е деактивиран за услугата Gmail. Моля, свържете се с вашия администратор, за да активира услугата Gmail за вашия акаунт.",
"GmailArchiveFolderNameOverride": "Архив",
"HoverActionOption_Archive": "Архивиране",
"HoverActionOption_Delete": "Изтриване",
"HoverActionOption_MoveJunk": "Преместване в Нежелани",
"HoverActionOption_ToggleFlag": "Отбелязване / Без отбелязване",
"HoverActionOption_ToggleRead": "Прочетено / Непрочетено",
"ImageRenderingDisabled": "Показването на изображения е деактивирано за това съобщение.",
"ImapAdvancedSetupDialog_AuthenticationMethod": "Метод за удостоверяване",
"ImapAdvancedSetupDialog_ConnectionSecurity": "Сигурност на връзката",
"IMAPAdvancedSetupDialog_ValidationAuthMethodRequired": "Изисква се метод за удостоверяване",
"IMAPAdvancedSetupDialog_ValidationConnectionSecurityRequired": "Изисква се тип сигурност на връзката",
"IMAPAdvancedSetupDialog_ValidationDisplayNameRequired": "Изисква се показвано име",
"IMAPAdvancedSetupDialog_ValidationEmailInvalid": "Моля, въведете валиден имейл адрес",
"IMAPAdvancedSetupDialog_ValidationEmailRequired": "Изисква се имейл адрес",
"IMAPAdvancedSetupDialog_ValidationErrorTitle": "Моля, проверете следното:",
"IMAPAdvancedSetupDialog_ValidationIncomingPortInvalid": "Входящият порт трябва да е между 1-65535",
"IMAPAdvancedSetupDialog_ValidationIncomingPortRequired": "Изисква се порт на входящия сървър",
"IMAPAdvancedSetupDialog_ValidationIncomingServerRequired": "Изисква се адрес на входящия сървър",
"IMAPAdvancedSetupDialog_ValidationOutgoingPasswordRequired": "Изисква се парола на изходящия сървър",
"IMAPAdvancedSetupDialog_ValidationOutgoingPortInvalid": "Изходящият порт трябва да е между 1-65535",
"IMAPAdvancedSetupDialog_ValidationOutgoingPortRequired": "Изисква се порт на изходящия сървър",
"IMAPAdvancedSetupDialog_ValidationOutgoingServerRequired": "Изисква се адрес на изходящия сървър",
"IMAPAdvancedSetupDialog_ValidationOutgoingUsernameRequired": "Изисква се потребителско име на изходящия сървър",
"IMAPAdvancedSetupDialog_ValidationPasswordRequired": "Изисква се парола",
"IMAPAdvancedSetupDialog_ValidationUsernameRequired": "Изисква се потребителско име",
"ImapAuthenticationMethod_Auto": "Автоматично",
"ImapAuthenticationMethod_CramMD5": "CRAM-MD5",
"ImapAuthenticationMethod_DigestMD5": "DIGEST-MD5",
"ImapAuthenticationMethod_EncryptedPassword": "Криптирана парола",
"ImapAuthenticationMethod_None": "Без удостоверяване",
"ImapAuthenticationMethod_Ntlm": "NTLM",
"ImapAuthenticationMethod_Plain": "Нормална парола",
"ImapConnectionSecurity_Auto": "Автоматично",
"ImapConnectionSecurity_None": "Няма",
"ImapConnectionSecurity_SslTls": "SSL/TLS",
"ImapConnectionSecurity_StartTls": "STARTTLS",
"IMAPSetupDialog_AccountType": "Тип на акаунта",
"IMAPSetupDialog_ValidationSuccess_Title": "Успешно",
"IMAPSetupDialog_ValidationSuccess_Message": "Успешно валидиране",
"IMAPSetupDialog_SaveImapSuccess_Title": "Success",
"IMAPSetupDialog_SaveImapSuccess_Message": "IMAP settings saved successfuly.",
"IMAPSetupDialog_ValidationFailed_Title": "Неуспешно валидиране на IMAP сървъра.",
"IMAPSetupDialog_CertificateAllowanceRequired_Row0": "Този сървър изисква установяване на защитена SSL връзка, за да продължи. Моля, потвърдете данните за сертификата по-долу.",
"IMAPSetupDialog_CertificateAllowanceRequired_Row1": "Разрешете защитената връзка, за да продължите да настройвате акаунта си.",
"IMAPSetupDialog_CertificateDenied": "Потребителят не е разрешил защитената връзка със сертификата.",
"IMAPSetupDialog_CertificateIssuer": "Издател",
"IMAPSetupDialog_CertificateSubject": "Тема",
"IMAPSetupDialog_CertificateValidFrom": "Валиден от",
"IMAPSetupDialog_CertificateValidTo": "Валиден до",
"IMAPSetupDialog_CertificateView": "Преглед на сертификата",
"IMAPSetupDialog_ConnectionFailedMessage": "Връзката с IMAP е неуспешна.",
"IMAPSetupDialog_ConnectionFailedTitle": "Връзката е неуспешна",
"IMAPSetupDialog_DisplayName": "Показвано име",
"IMAPSetupDialog_DisplayNamePlaceholder": "напр. Иван Иванов",
"IMAPSetupDialog_IncomingMailServer": "Сървър за входяща поща",
"IMAPSetupDialog_IncomingMailServerPort": "Порт",
"IMAPSetupDialog_IMAPSettings": "Настройки на IMAP сървъра",
"IMAPSetupDialog_SMTPSettings": "Настройки на SMTP сървъра",
"IMAPSetupDialog_MailAddress": "Имейл адрес",
"IMAPSetupDialog_MailAddressPlaceholder": "nyakoy@primer.com",
"IMAPSetupDialog_OutgoingMailServer": "Сървър за изходяща поща (SMTP)",
"IMAPSetupDialog_OutgoingMailServerPassword": "Парола на изходящия сървър",
"IMAPSetupDialog_OutgoingMailServerPort": "Порт",
"IMAPSetupDialog_OutgoingMailServerRequireAuthentication": "Изходящият сървър изисква удостоверяване",
"IMAPSetupDialog_OutgoingMailServerUsername": "Потребителско име на изходящия сървър",
"IMAPSetupDialog_Password": "Парола",
"IMAPSetupDialog_RequireSSLForIncomingMail": "Изисква SSL за входящата поща",
"IMAPSetupDialog_RequireSSLForOutgoingMail": "Изисква SSL за изходящата поща",
"IMAPSetupDialog_Title": "Разширено конфигуриране на IMAP",
"IMAPSetupDialog_Username": "Потребител",
"IMAPSetupDialog_UsernamePlaceholder": "ivanivanov, ivanivanov@primer.com, domain/ivanivanov",
"IMAPSetupDialog_UseSameConfig": "Използване на същото потребителско име и парола за изпращане на имейли",
"Info_AccountCreatedMessage": "{0} е създаден",
"Info_AccountCreatedTitle": "Създаване на акаунт",
"Info_AccountCreationFailedTitle": "Неуспешно създаване на акаунт",
"Info_AccountDeletedMessage": "{0} е изтрит успешно.",
"Info_AccountDeletedTitle": "Акаунтът е изтрит",
"Info_AccountIssueFixFailedTitle": "Неуспешно",
"Info_AccountIssueFixSuccessMessage": "Отстранени са всички проблеми с акаунтите.",
"Info_AccountIssueFixSuccessTitle": "Успешно",
"Info_AttachmentOpenFailedMessage": "Не може да се отвори този прикачен файл.",
"Info_AttachmentOpenFailedTitle": "Неуспешно",
"Info_AttachmentSaveFailedMessage": "Не може да се запази този прикачен файл.",
"Info_AttachmentSaveFailedTitle": "Неуспешно",
"Info_AttachmentSaveSuccessMessage": "Прикаченият файл е запазен.",
"Info_AttachmentSaveSuccessTitle": "Запазен прикачен файл",
"Info_BackgroundExecutionDeniedMessage": "Изпълнението на приложението на заден план е отказано. Това може да повлияе на синхронизацията на заден план и известията в реално време.",
"Info_BackgroundExecutionDeniedTitle": "Отказано изпълнение на задан план",
"Info_BackgroundExecutionUnknownErrorMessage": "Възникна неизвестно изключение при регистриране на синхронизатора на заден план.",
"Info_BackgroundExecutionUnknownErrorTitle": "Неуспешно изпълнение на заден план",
"Info_CantDeletePrimaryAliasMessage": "Основният псевдоним не може да бъде изтрит. Моля, променете псевдонима си, преди да изтриете този",
"Info_ComposerMissingMIMEMessage": "MIME файлът не можа да се намери. Синхронизирането може да помогне.",
"Info_ComposerMissingMIMETitle": "Неуспешно",
"Info_ContactExistsMessage": "Този контакт вече е в списъка с получатели.",
"Info_ContactExistsTitle": "Контактът съществува",
"Info_DraftFolderMissingMessage": "За този акаунт липсва папка Чернови. Моля, проверете настройките на акаунта си.",
"Info_DraftFolderMissingTitle": "Липсва папка Чернови",
"Info_FailedToOpenFileMessage": "Файлът може да бъде премахнат от диска.",
"Info_FailedToOpenFileTitle": "Неуспешно стартиране на файла.",
"Info_FileLaunchFailedTitle": "Неуспешно стартиране на файла",
"Info_InvalidAddressMessage": "„{0}“ не е валиден имейл адрес.",
"Info_InvalidAddressTitle": "Невалиден адрес",
"Info_InvalidMoveTargetMessage": "Не можете да преместите избраните писма в тази папка.",
"Info_InvalidMoveTargetTitle": "Невалидна цел за преместване",
"Info_LogsNotFoundMessage": "Няма дневници за споделяне.",
"Info_LogsNotFoundTitle": "Дневниците не са намерени",
"Info_LogsSavedMessage": "{0} се запазва в избраната папка.",
"Info_LogsSavedTitle": "Запазено",
"Info_MailListSizeResetSuccessMessage": "Размерът на пощенския списък е нулиран.",
"Info_MailRenderingFailedMessage": "Тази поща е повредена или не може да бъде отворена.\n{0}",
"Info_MailRenderingFailedTitle": "Неуспешно визуализиране",
"Info_MessageCorruptedMessage": "Това съобщение е повредено.",
"Info_MessageCorruptedTitle": "Грешка",
"Info_MissingFolderMessage": "{0} не съществува за този акаунт.",
"Info_MissingFolderTitle": "Липсваща папка",
"Info_PDFSaveFailedTitle": "Неуспешно записване на PDF файл",
"Info_PDFSaveSuccessMessage": "PDF файлът е записан в {0}",
"Info_PDFSaveSuccessTitle": "Успешно",
"Info_PurchaseExistsMessage": "Изглежда, че този продукт вече е бил закупен преди.",
"Info_PurchaseExistsTitle": "Съществуващ продукт",
"Info_PurchaseThankYouMessage": "Благодарим ви",
"Info_PurchaseThankYouTitle": "Покупката е успешна",
"Info_RequestCreationFailedTitle": "Неуспешно създаване на заявки",
"Info_ReviewNetworkErrorMessage": "Имаше мрежов проблем с прегледа ви.",
"Info_ReviewNetworkErrorTitle": "Мрежов проблем",
"Info_ReviewNewMessage": "Оценяваме всички отзиви. Благодарим ви за прегледа!",
"Info_ReviewSuccessTitle": "Благодарим ви",
"Info_ReviewUnknownErrorMessage": "Имаше неизвестен проблем с прегледа ви. ({0})",
"Info_ReviewUnknownErrorTitle": "Неизвестна грешка",
"Info_ReviewUpdatedMessage": "Благодарим ви за актуализирания преглед.",
"Info_SignatureDisabledMessage": "Деактивиран подпис за този акаунт",
"Info_SignatureDisabledTitle": "Успешно",
"Info_SignatureSavedMessage": "Новият подпис се запазва",
"Info_SignatureSavedTitle": "Успешно",
"Info_SyncCanceledMessage": "Отменено",
"Info_SyncCanceledTitle": "Синхронизиране",
"Info_SyncFailedTitle": "Неуспешна синхронизация",
"Info_UnsubscribeErrorMessage": "Неуспешно отписване",
"Info_UnsubscribeLinkInvalidMessage": "Тази връзка за отписване е невалидна. Неуспешно отписване от списъка.",
"Info_UnsubscribeLinkInvalidTitle": "Невалиден Uri за отписване",
"Info_UnsubscribeSuccessMessage": "Успешно се отписахте от {0}.",
"Info_UnsupportedFunctionalityDescription": "Тази функционалност все още не е реализирана.",
"Info_UnsupportedFunctionalityTitle": "Не се поддържа",
"InfoBarAction_Enable": "Активиране",
"InfoBarMessage_SynchronizationDisabledFolder": "Синхронизирането на тази папка е деактивирано.",
"InfoBarTitle_SynchronizationDisabledFolder": "Изключена папка",
"Justify": "Двустранно",
"Left": "Ляво",
"Link": "Връзка",
"LinkedAccountsCreatePolicyMessage": "Трябва да имате поне 2 акаунта, за да създадете връзка.\nВръзката ще бъде премахната при запазване.",
"LinkedAccountsTitle": "Свързани акаунти",
"MailItemNoSubject": "Без тема",
"MailOperation_AlwaysMoveFocused": "Винаги да се преместват в На фокус",
"MailOperation_AlwaysMoveOther": "Винаги да се преместват в Други",
"MailOperation_Archive": "Архивиране",
"MailOperation_ClearFlag": "Без отбелязване",
"MailOperation_DarkEditor": "Тъмна",
"MailOperation_Delete": "Изтриване",
"MailOperation_ExportPDF": "Експортиране в PDF",
"MailOperation_Find": "Намиране",
"MailOperation_Forward": "Препращане",
"MailOperation_Ignore": "Игнориране",
"MailOperation_LightEditor": "Светла",
"MailOperation_MarkAsJunk": "Маркиране като нежелано",
"MailOperation_MarkAsRead": "Маркиране като прочетено",
"MailOperation_MarkAsUnread": "Маркиране като непрочетено",
"MailOperation_MarkNotJunk": "Не е нежелано",
"MailOperation_Move": "Преместване",
"MailOperation_MoveFocused": "Преместване в На фокус",
"MailOperation_MoveJunk": "Преместване в Нежелани",
"MailOperation_MoveOther": "Преместване в Други",
"MailOperation_Navigate": "Отиване",
"MailOperation_Print": "Отпечатване",
"MailOperation_Reply": "Отговор",
"MailOperation_ReplyAll": "Отговор на всички",
"MailOperation_SaveAs": "Запазване като",
"MailOperation_SetFlag": "Отбелязване",
"MailOperation_Unarchive": "Разархивиране",
"MailOperation_ViewMessageSource": "Преглед на изходния код",
"MailOperation_Zoom": "Мащаб",
"MailsSelected": "{0} избран(и) елемент(и)",
"MarkFlagUnflag": "Отбелязано/Без отбелязване",
"MarkReadUnread": "Маркиране като прочетено/непрочетено",
"MenuManageAccounts": "Управление на акаунтите",
"MenuMergedAccountItemAccountsSuffix": " акаунти",
"MenuNewMail": "Нов имейл",
"MenuRate": "Оценете Wino",
"MenuSettings": "Настройки",
"MergedAccountCommonFolderArchive": "Архив",
"MergedAccountCommonFolderDraft": "Чернова",
"MergedAccountCommonFolderInbox": "Входящи",
"MergedAccountCommonFolderJunk": "Нежелани",
"MergedAccountCommonFolderSent": "Изпратени",
"MergedAccountCommonFolderTrash": "Изтрити",
"MergedAccountsAvailableAccountsTitle": "Налични акаунти",
"MessageSourceDialog_Title": "Източник на съобщението",
"More": "Още",
"MoreFolderNameOverride": "Още",
"MoveMailDialog_InvalidFolderMessage": "{0} не е валидна папка за тази поща.",
"MoveMailDialog_Title": "Изберете папка",
"NewAccountDialog_AccountName": "Име на акаунта",
"NewAccountDialog_AccountNameDefaultValue": "Личен",
"NewAccountDialog_AccountNamePlaceholder": "напр. Лична поща",
"NewAccountDialog_Title": "Добавяне на нов акаунт",
"NoMailSelected": "Не е избрано съобщение",
"NoMessageCrieteria": "Няма съобщения, които да отговарят на критериите ви за търсене",
"NoMessageEmptyFolder": "Тази папка е празна",
"Notifications_MultipleNotificationsMessage": "Имате {0} нови съобщения.",
"Notifications_MultipleNotificationsTitle": "Нов имейл",
"Notifications_WinoUpdatedMessage": "Вижте новата версия {0}",
"Notifications_WinoUpdatedTitle": "Wino Mail е актуализиран.",
"OnlineSearchFailed_Message": "Неуспешно търсене\n{0}\n\nПоказване на офлайн имейли.",
"OnlineSearchTry_Line1": "Не можете да намерите това, което търсите?",
"OnlineSearchTry_Line2": "Опитайте онлайн търсене.",
"Other": "Друго",
"PaneLengthOption_Default": "По подразбиране",
"PaneLengthOption_ExtraLarge": "Много голям",
"PaneLengthOption_Large": "Голям",
"PaneLengthOption_Medium": "Среден",
"PaneLengthOption_Micro": "Много малък",
"PaneLengthOption_Small": "Малък",
"Photos": "Снимки",
"PreparingFoldersMessage": "Подготовка на папките",
"ProtocolLogAvailable_Message": "Протоколните дневници са достъпни за диагностика.",
"ProviderDetail_Gmail_Description": "Акаунт в Google",
"ProviderDetail_iCloud_Description": "Акаунт в Apple iCloud",
"ProviderDetail_iCloud_Title": "iCloud",
"ProviderDetail_IMAP_Description": "Потребителски IMAP/SMTP сървър",
"ProviderDetail_IMAP_Title": "IMAP сървър",
"ProviderDetail_Yahoo_Description": "Акаунт в Yahoo",
"ProviderDetail_Yahoo_Title": "Yahoo Mail",
"QuickEventDialog_EventName": "Име на събитието",
"QuickEventDialog_IsAllDay": "Цял ден",
"QuickEventDialog_Location": "Местоположение",
"QuickEventDialog_RemindMe": "Напомнете ми",
"QuickEventDialogMoreDetailsButtonText": "Повече подробности",
"Reader_SaveAllAttachmentButtonText": "Запазване на всички прикачени файлове",
"Results": "Резултати",
"Right": "Дясно",
"SearchBarPlaceholder": "Търсене",
"SearchingIn": "Търсене в",
"SearchPivotName": "Резултати",
"SettingConfigureSpecialFolders_Button": "Конфигуриране",
"SettingsEditAccountDetails_IMAPConfiguration_Title": "Конфигурация на IMAP/SMTP",
"SettingsEditAccountDetails_IMAPConfiguration_Description": "Променете настройките на входящия/изходящия сървър.",
"SettingsAbout_Description": "Научете повече за Wino.",
"SettingsAbout_Title": "За приложението",
"SettingsAboutGithub_Description": "Към хранилището на GitHub за проследяване на проблеми.",
"SettingsAboutGithub_Title": "GitHub",
"SettingsAboutVersion": "Версия ",
"SettingsAboutWinoDescription": "Лек пощенски клиент за семейства устройства с Windows.",
"SettingsAccentColor_Description": "Промяна на цвета на акцента в приложението",
"SettingsAccentColor_Title": "Цвят на акцента",
"SettingsAccentColor_UseWindowsAccentColor": "Използване на акцентния цвят на Windows",
"SettingsAccountManagementAppendMessage_Description": "Създаване на копие на съобщението в папка „Изпратени“ след изпращане на черновата. Включете това, ако не виждате писмата си след изпращането им в папка „Изпратени“.",
"SettingsAccountManagementAppendMessage_Title": "Добавяне на съобщенията в папка „Изпратени“",
"SettingsAccountName_Description": "Промяна на името на акаунта.",
"SettingsAccountName_Title": "Име на акаунта",
"SettingsApplicationTheme_Description": "Персонализирайте Wino с различни потребителски теми за приложението, които ви харесват.",
"SettingsApplicationTheme_Title": "Тема на приложението",
"SettingsAppPreferences_CloseBehavior_Description": "Какво да се случи, когато затворите приложението?",
"SettingsAppPreferences_CloseBehavior_Title": "Поведение при затваряне на приложението",
"SettingsAppPreferences_Description": "Общи настройки / предпочитания за Wino Mail.",
"SettingsAppPreferences_SearchMode_Description": "Задайте дали Wino да проверява първо получените писма при търсене или да попита вашия пощенски сървър онлайн. Местното търсене винаги е по-бързо и винаги можете да направите онлайн търсене, ако вашата поща не е в резултатите.",
"SettingsAppPreferences_SearchMode_Local": "Локално",
"SettingsAppPreferences_SearchMode_Online": "Онлайн",
"SettingsAppPreferences_SearchMode_Title": "Режим на търсене по подразбиране",
"SettingsAppPreferences_ServerBackgroundingMode_Invisible_Description": "Wino Mail ще продължи да работи на заден план. Ще бъдете уведомявани за пристигането на нови имейли.",
"SettingsAppPreferences_ServerBackgroundingMode_Invisible_Title": "Работа на заден план",
"SettingsAppPreferences_ServerBackgroundingMode_MinimizeTray_Description": "Wino Mail ще продължи да работи в системната област. Можете да го стартирате, като щракнете върху иконата. Ще бъдете уведомявани при пристигането на нови имейли.",
"SettingsAppPreferences_ServerBackgroundingMode_MinimizeTray_Title": "Минимизиране в системната област",
"SettingsAppPreferences_ServerBackgroundingMode_Terminate_Description": "Wino Mail няма да продължи да работи никъде. Няма да бъдете уведомявани за пристигането на нови имейли. Стартирайте отново Wino Mail, за да продължите синхронизирането на пощата.",
"SettingsAppPreferences_ServerBackgroundingMode_Terminate_Title": "Прекратяване",
"SettingsAppPreferences_StartupBehavior_Description": "Позволете на Wino Mail да се стартира минимизиран при стартиране на Windows. Винаги разрешавайте да получава известия.",
"SettingsAppPreferences_StartupBehavior_Disable": "Деактивиране",
"SettingsAppPreferences_StartupBehavior_Disabled": "Wino Mail няма да се стартира при стартиране на Windows. Това ще доведе до пропускане на известия при рестартиране на компютъра.",
"SettingsAppPreferences_StartupBehavior_DisabledByPolicy": "Вашият администратор или групови политики са забранили стартирането на приложения при начално стартиране. Поради това Wino Mail не може да бъде настроен да се стартира при стартиране на Windows.",
"SettingsAppPreferences_StartupBehavior_DisabledByUser": "Моля, отидете в Мениджър на задачите -> раздел Автоматично стартиращи се приложения, за да разрешите на Wino Mail да се стартира при стартиране на Windows.",
"SettingsAppPreferences_StartupBehavior_Enable": "Активиране",
"SettingsAppPreferences_StartupBehavior_Enabled": "Wino Mail е настроен успешно да се стартира на заден план при стартиране на Windows.",
"SettingsAppPreferences_StartupBehavior_FatalError": "Възникна фатална грешка при промяна на режима на стартиране на Wino Mail.",
"SettingsAppPreferences_StartupBehavior_Title": "Стартиране в минимизиран вид при стартиране на Windows",
"SettingsAppPreferences_Title": "Предпочитания за приложението",
"SettingsAutoSelectNextItem_Description": "Избиране на следващия елемент, след като изтриете или преместите имейл.",
"SettingsAutoSelectNextItem_Title": "Автоматично избиране на следващия елемент",
"SettingsAvailableThemes_Description": "Изберете тема от собствената колекция на Wino по ваш вкус или приложете свои собствени теми.",
"SettingsAvailableThemes_Title": "Налични теми",
"SettingsCalendarSettings_Description": "Променете първия ден от седмицата, височината на часовата клетка и други...",
"SettingsCalendarSettings_Title": "Настройки на календара",
"SettingsComposer_Title": "Съставяне",
"SettingsComposerFont_Title": "Шрифт по подразбиране за съставяне",
"SettingsComposerFontFamily_Description": "Промяна на шрифтовото семейство и размера на шрифта по подразбиране за съставяне на имейли.",
"SettingsConfigureSpecialFolders_Description": "Задаване на папки със специални функции. Папки като Архив, Входящи и Чернови са от съществено значение за правилното функциониране на Wino.",
"SettingsConfigureSpecialFolders_Title": "Конфигуриране на системните папки",
"SettingsCustomTheme_Description": "Създайте своя собствена тема с персонализиран тапет и цвят на акцента.",
"SettingsCustomTheme_Title": "Потребителска тема",
"SettingsDeleteAccount_Description": "Изтриване на всички имейли и идентификационни данни, свързани с този акаунт.",
"SettingsDeleteAccount_Title": "Изтриване на този акаунт",
"SettingsDeleteProtection_Description": "Should Wino ask you for confirmation every time you try to permanently delete a mail using Shift + Del keys?",
"SettingsDeleteProtection_Title": "Защита от окончателно изтриване",
"SettingsDiagnostics_Description": "За разработчици",
"SettingsDiagnostics_DiagnosticId_Description": "Споделете този идентификационен номер с разработчиците, когато ви помолят, за да получите помощ за проблемите, с които се сблъсквате в Wino Mail.",
"SettingsDiagnostics_DiagnosticId_Title": "Идентификатор за диагностика",
"SettingsDiagnostics_Title": "Диагностика",
"SettingsDiscord_Description": "Получавайте редовно актуализации за разработката, включвайте се в обсъждания на пътната карта и предоставяйте обратна връзка.",
"SettingsDiscord_Title": "Канал в Discord",
"SettingsEditLinkedInbox_Description": "Добавяне/премахване на акаунти, преименуване или прекъсване на връзката между акаунтите.",
"SettingsEditLinkedInbox_Title": "Редактиране на свързаната входяща поща",
"SettingsElementTheme_Description": "Избор на тема на Windows за Wino",
"SettingsElementTheme_Title": "Цветови режим",
"SettingsElementThemeSelectionDisabled": "Изборът на цветови режим е забранен, когато е избрана тема на приложението, различна от тази по подразбиране.",
"SettingsEnableHoverActions_Title": "Активиране на действията при поставяне на курсора",
"SettingsEnableIMAPLogs_Description": "Активирайте тази опция, за да предоставите подробна информация за проблемите със свързаността на IMAP, които сте имали по време на настройката на IMAP сървъра.",
"SettingsEnableIMAPLogs_Title": "Активиране на дневниците на IMAP протокола",
"SettingsEnableLogs_Description": "Може да ми трябват дневниците за сривове, за да диагностицирам проблемите, които сте открили в GitHub. Нито един от дневниците няма да разкрие публично вашите идентификационни данни или чувствителна информация.",
"SettingsEnableLogs_Title": "Активиране на дневниците",
"SettingsEnableSignature": "Активиране на подписа",
"SettingsExpandOnStartup_Description": "Задайте дали Wino да разгръща папките на този акаунт при стартиране.",
"SettingsExpandOnStartup_Title": "Разгръщане на менюто при стартиране",
"SettingsExternalContent_Description": "Управление на настройките за външно съдържание при визуализиране на имейли.",
"SettingsExternalContent_Title": "Външно съдържание",
"SettingsFocusedInbox_Description": "Задайте дали входящата поща да бъде разделена на две като На фокус - Други.",
"SettingsFocusedInbox_Title": "Входящи на фокус",
"SettingsFolderMenuStyle_Description": "Промяна на това дали папките на акаунта трябва да са вложени в менюто на акаунта или не. Изключете тази опция, ако ви харесва старата система на менютата в Поща на Windows",
"SettingsFolderMenuStyle_Title": "Създаване на вложени папки",
"SettingsFolderOptions_Description": "Промяна настройките на отделните папки, като например разрешаване/забрана на синхронизацията или показване/скриване на значката за непрочетените.",
"SettingsFolderOptions_Title": "Конфигурация на папките",
"SettingsFolderSync_Description": "Активиране или деактивиране синхронизирането на определени папки.",
"SettingsFolderSync_Title": "Синхронизиране на папките",
"SettingsFontFamily_Title": "Семейство шрифтове",
"SettingsFontPreview_Title": "Преглед",
"SettingsFontSize_Title": "Размер на шрифта",
"SettingsHoverActionCenter": "Централно действие",
"SettingsHoverActionLeft": "Ляво действие",
"SettingsHoverActionRight": "Дясно действие",
"SettingsHoverActions_Description": "Изберете 3 действия, които да се показват при преминаване с курсора над имейлите.",
"SettingsHoverActions_Title": "Действия при преминаване с мишката",
"SettingsLanguage_Description": "Промяна на езика за показване на Wino.",
"SettingsLanguage_Title": "Език на показване",
"SettingsLanguageTime_Description": "Език на показване на Wino, предпочитан формат на часа.",
"SettingsLanguageTime_Title": "Език и формат на часа",
"SettingsLinkAccounts_Description": "Сливане на няколко акаунта в един. Виждайте имейлите заедно в една входяща кутия.",
"SettingsLinkAccounts_Title": "Създаване на свързани акаунти",
"SettingsLinkedAccountsSave_Description": "Промяна на текущото свързване с новите акаунти.",
"SettingsLinkedAccountsSave_Title": "Запазване на промените",
"SettingsLoadImages_Title": "Автоматично зареждане на изображенията",
"SettingsLoadPlaintextLinks_Title": "Конвертиране на обикновените текстови връзки в такива, върху които може да се клика",
"SettingsLoadStyles_Title": "Автоматично зареждане на стиловете",
"SettingsMailListActionBar_Description": "Скриване/показване на лентата за действия в горната част на списъка със съобщения.",
"SettingsMailListActionBar_Title": "Показване на действията в списъка с имейлите",
"SettingsMailSpacing_Description": "Настройте отстоянието между имейлите.",
"SettingsMailSpacing_Title": "Интервал между имейлите",
"SettingsManageAccountSettings_Description": "Известия, подписи, синхронизация и други настройки за всеки акаунт.",
"SettingsManageAccountSettings_Title": "Управление на настройките на акаунта",
"SettingsManageAliases_Description": "Вижте псевдонимите на имейлите, назначени за този акаунт, актуализирайте ги или ги изтрийте.",
"SettingsManageAliases_Title": "Псевдоними",
"SettingsEditAccountDetails_Title": "Редактиране на данните на акаунта",
"SettingsEditAccountDetails_Description": "Променете името на акаунта, името на подателя и задайте нов цвят, ако желаете.",
"SettingsManageLink_Description": "Преместете елементите, за да добавите нова връзка или да премахнете съществуваща връзка.",
"SettingsManageLink_Title": "Управление на връзката",
"SettingsMarkAsRead_Description": "Променете какво трябва да се случи с избрания елемент.",
"SettingsMarkAsRead_DontChange": "Да не се маркира автоматично елемента като прочетен",
"SettingsMarkAsRead_SecondsToWait": "Секунди за изчакване: ",
"SettingsMarkAsRead_Timer": "При преглед в прозореца за четене",
"SettingsMarkAsRead_Title": "Маркиране на елемента като прочетен",
"SettingsMarkAsRead_WhenSelected": "Когато е избран",
"SettingsMessageList_Description": "Променете начина на организиране на съобщенията в списъка с имейли.",
"SettingsMessageList_Title": "Списък със съобщения",
"SettingsNoAccountSetupMessage": "Все още не сте настроили никакви акаунти.",
"SettingsNotifications_Description": "Включване или изключване на известията за този акаунт.",
"SettingsNotifications_Title": "Известия",
"SettingsNotificationsAndTaskbar_Description": "Променете дали да се показват известия и значка в лентата на задачите за този акаунт.",
"SettingsNotificationsAndTaskbar_Title": "Известия и лента на задачите",
"SettingsOptions_Title": "Настройки",
"SettingsPaneLengthReset_Description": "Възстановете първоначалния размер на списъка с имейли, ако имате проблеми с него.",
"SettingsPaneLengthReset_Title": "Възстановяване размера на списъка с имейли",
"SettingsPaypal_Description": "Покажете много повече любов ❤️ Всички дарения са добре дошли.",
"SettingsPaypal_Title": "Дарете чрез PayPal",
"SettingsPersonalization_Description": "Променете външния вид на Wino, както ви харесва.",
"SettingsPersonalization_Title": "Персонализация",
"SettingsPersonalizationMailDisplayCompactMode": "Компактен режим",
"SettingsPersonalizationMailDisplayMediumMode": "Среден режим",
"SettingsPersonalizationMailDisplaySpaciousMode": "Просторен режим",
"SettingsPrefer24HourClock_Description": "Часовете на получената поща ще се показват в 24-часов формат вместо в 12-часов (AM/PM)",
"SettingsPrefer24HourClock_Title": "Показване на часовете в 24-часов формат",
"SettingsPrivacyPolicy_Description": "Прегледайте политиката за поверителност.",
"SettingsPrivacyPolicy_Title": "Политика за поверителност",
"SettingsReadComposePane_Description": "Шрифтове, външно съдържание.",
"SettingsReadComposePane_Title": "Четене и съставяне",
"SettingsReader_Title": "Четене",
"SettingsReaderFont_Title": "Шрифт по подразбиране за четене",
"SettingsReaderFontFamily_Description": "Променете шрифтовото семейство и размера на шрифта по подразбиране за четене на имейли.",
"SettingsRenameMergeAccount_Description": "Променете показваното име на свързаните акаунти.",
"SettingsRenameMergeAccount_Title": "Преименуване",
"SettingsReorderAccounts_Description": "Променете реда на акаунтите в списъка с акаунти.",
"SettingsReorderAccounts_Title": "Пренареждане на акаунтите",
"SettingsSemanticZoom_Description": "Това ще ви позволи да кликнете върху заглавията в списъка със съобщения и да преминете към определена дата",
"SettingsSemanticZoom_Title": "Семантично увеличение за заглавия с дати",
"SettingsShowPreviewText_Description": "Скриване/показване на текста за визуализация.",
"SettingsShowPreviewText_Title": "Показване визуализация на текста",
"SettingsShowSenderPictures_Description": "Скриване/показване на миниатюрите на снимките на изпращача.",
"SettingsShowSenderPictures_Title": "Показване на аватарите на подателите",
"SettingsEnableGravatarAvatars_Title": "Gravatar",
"SettingsEnableGravatarAvatars_Description": "Use gravatar (if available) as sender picture",
"SettingsEnableFavicons_Title": "Domain icons (Favicons)",
"SettingsEnableFavicons_Description": "Use domain favicons (if available) as sender picture",
"SettingsMailList_ClearAvatarsCache_Button": "Clear cached avatars",
"SettingsSignature_AddCustomSignature_Button": "Добавяне на подпис",
"SettingsSignature_AddCustomSignature_Title": "Добавяне на персонализиран подпис",
"SettingsSignature_DeleteSignature_Title": "Изтриване на подписа",
"SettingsSignature_Description": "Управление на подписите на акаунтите",
"SettingsSignature_EditSignature_Title": "Редактиране на подписа",
"SettingsSignature_ForFollowingMessages_Title": "За отговори/препратки",
"SettingsSignature_ForNewMessages_Title": "За нови съобщения",
"SettingsSignature_NoneSignatureName": "Няма",
"SettingsSignature_SignatureDefaults": "Параметри на подписа по подразбиране",
"SettingsSignature_Signatures": "Подписи",
"SettingsSignature_Title": "Подпис",
"SettingsStartupItem_Description": "Основен елемент от акаунта за зареждане на Входящи при стартиране.",
"SettingsStartupItem_Title": "Елемент за стартиране",
"SettingsStore_Description": "Покажете малко любов ❤️",
"SettingsStore_Title": "Оценете ни в магазина",
"SettingsTaskbarBadge_Description": "Показване броя на непрочетените писма в иконата в лентата на задачите.",
"SettingsTaskbarBadge_Title": "Значка на лентата на задачите",
"SettingsThreads_Description": "Организиране на съобщенията в разговори.",
"SettingsThreads_Title": "Групиране в разговори",
"SettingsUnlinkAccounts_Description": "Премахване на връзката между акаунтите. Това няма да доведе до изтриване на акаунтите ви.",
"SettingsUnlinkAccounts_Title": "Премахване на връзката между акаунтите",
"SettingsMailRendering_ActionLabels_Title": "Action labels",
"SettingsMailRendering_ActionLabels_Description": "Show action labels.",
"SignatureDeleteDialog_Message": "Наистина ли искате да изтриете подписа „{0}“?",
"SignatureDeleteDialog_Title": "Изтриване на подписа",
"SignatureEditorDialog_SignatureName_Placeholder": "Име на вашия подпис",
"SignatureEditorDialog_SignatureName_TitleEdit": "Текущо име на подписа: {0}",
"SignatureEditorDialog_SignatureName_TitleNew": "Име на подписа",
"SignatureEditorDialog_Title": "Редактор на подписи",
"SortingOption_Date": "по дата",
"SortingOption_Name": "по име",
"StoreRatingDialog_MessageFirstLine": "Всички отзиви се оценяват и ще направят Wino много по-добър в бъдеще. Искате ли да оцените Wino в Microsoft Store?",
"StoreRatingDialog_MessageSecondLine": "Искате ли да оцените Wino Mail в Microsoft Store?",
"StoreRatingDialog_Title": "Wino ви харесва?",
"SynchronizationFolderReport_Failed": "неуспешна синхронизация",
"SynchronizationFolderReport_Success": "актуални",
"SystemFolderConfigDialog_ArchiveFolderDescription": "Архивираните съобщения ще бъдат преместени тук.",
"SystemFolderConfigDialog_ArchiveFolderHeader": "Папка Архив",
"SystemFolderConfigDialog_DeletedFolderDescription": "Изтритите съобщения ще бъдат преместени тук.",
"SystemFolderConfigDialog_DeletedFolderHeader": "Изтрита папка",
"SystemFolderConfigDialog_DraftFolderDescription": "Новите писма/отговори ще бъдат създавани тук.",
"SystemFolderConfigDialog_DraftFolderHeader": "Папка Чернови",
"SystemFolderConfigDialog_JunkFolderDescription": "Всички спам/нежелани имейли ще бъдат тук.",
"SystemFolderConfigDialog_JunkFolderHeader": "Папка за нежелана поща/спам",
"SystemFolderConfigDialog_MessageFirstLine": "Този IMAP сървър не поддържа разширението SPECIAL-USE, поради което Wino не може да настрои правилно системните папки.",
"SystemFolderConfigDialog_MessageSecondLine": "Моля, изберете подходящите папки за конкретни функционалности.",
"SystemFolderConfigDialog_SentFolderDescription": "Папка, в която ще се съхраняват изпратените съобщения.",
"SystemFolderConfigDialog_SentFolderHeader": "Папка Изпратени",
"SystemFolderConfigDialog_Title": "Конфигуриране на системните папки",
"SystemFolderConfigDialogValidation_DuplicateSystemFolders": "Някои от системните папки се използват повече от веднъж в конфигурацията.",
"SystemFolderConfigDialogValidation_InboxSelected": "Не можете да присвоите папка Входящи към друга системна папка.",
"SystemFolderConfigSetupSuccess_Message": "Системните папки са успешно конфигурирани.",
"SystemFolderConfigSetupSuccess_Title": "Настройка на системните папки",
"TestingImapConnectionMessage": "Тестване на връзката със сървъра...",
"TitleBarServerDisconnectedButton_Description": "Wino е изключен от мрежата. Щракнете върху Повторно свързване, за да възстановите връзката.",
"TitleBarServerDisconnectedButton_Title": "няма връзка",
"TitleBarServerReconnectButton_Title": "повторно свързване",
"TitleBarServerReconnectingButton_Title": "свързване",
"Today": "Днес",
"UnknownAddress": "неизвестен адрес",
"UnknownDateHeader": "Неизвестна дата",
"UnknownGroupAddress": "неизвестен адрес на пощенската група",
"UnknownSender": "Неизвестен подател",
"Unsubscribe": "Отписване",
"ViewContactDetails": "Вижте подробностите",
"WinoUpgradeDescription": "Wino предлага 3 безплатни акаунта за начало. Ако имате нужда от повече от 3 акаунта, моля, надстройте",
"WinoUpgradeMessage": "Надграждане до неограничен брой акаунти",
"WinoUpgradeRemainingAccountsMessage": "Използвани са {0} от {1} безплатни акаунта.",
"Yesterday": "Вчера",
"SettingsAppPreferences_EmailSyncInterval_Title": "Email sync interval",
"SettingsAppPreferences_EmailSyncInterval_Description": "Automatic email synchronization interval (minutes). This setting will be applied only after restarting Wino Mail."
}

View File

@@ -22,6 +22,10 @@
"AccountPickerDialog_Title": "Pick an account", "AccountPickerDialog_Title": "Pick an account",
"AccountSettingsDialog_AccountName": "Sender Display Name", "AccountSettingsDialog_AccountName": "Sender Display Name",
"AccountSettingsDialog_AccountNamePlaceholder": "eg. John Doe", "AccountSettingsDialog_AccountNamePlaceholder": "eg. John Doe",
"AccountDetailsPage_Title": "Account info",
"AccountDetailsPage_Description": "Change the name of the account in Wino and set desired sender name.",
"AccountDetailsPage_ColorPicker_Title": "Account color",
"AccountDetailsPage_ColorPicker_Description": "Assign a new account color to colorize its symbol in the list.",
"AddHyperlink": "Add", "AddHyperlink": "Add",
"AppCloseBackgroundSynchronizationWarningTitle": "Background Synchronization", "AppCloseBackgroundSynchronizationWarningTitle": "Background Synchronization",
"AppCloseStartupLaunchDisabledWarningMessageFirstLine": "Application has not been set to launch on Windows startup.", "AppCloseStartupLaunchDisabledWarningMessageFirstLine": "Application has not been set to launch on Windows startup.",
@@ -256,6 +260,11 @@
"ImapConnectionSecurity_SslTls": "SSL/TLS", "ImapConnectionSecurity_SslTls": "SSL/TLS",
"ImapConnectionSecurity_StartTls": "STARTTLS", "ImapConnectionSecurity_StartTls": "STARTTLS",
"IMAPSetupDialog_AccountType": "Account type", "IMAPSetupDialog_AccountType": "Account type",
"IMAPSetupDialog_ValidationSuccess_Title": "Success",
"IMAPSetupDialog_ValidationSuccess_Message": "Validation successful",
"IMAPSetupDialog_SaveImapSuccess_Title": "Success",
"IMAPSetupDialog_SaveImapSuccess_Message": "IMAP settings saved successfuly.",
"IMAPSetupDialog_ValidationFailed_Title": "IMAP Server validation failed.",
"IMAPSetupDialog_CertificateAllowanceRequired_Row0": "This server is requesting a SSL handshake to continue. Please confirm the certificate details below.", "IMAPSetupDialog_CertificateAllowanceRequired_Row0": "This server is requesting a SSL handshake to continue. Please confirm the certificate details below.",
"IMAPSetupDialog_CertificateAllowanceRequired_Row1": "Allow the handshake to continue setting up your account.", "IMAPSetupDialog_CertificateAllowanceRequired_Row1": "Allow the handshake to continue setting up your account.",
"IMAPSetupDialog_CertificateDenied": "User didn't authorize the handshake with the certificate.", "IMAPSetupDialog_CertificateDenied": "User didn't authorize the handshake with the certificate.",
@@ -270,6 +279,8 @@
"IMAPSetupDialog_DisplayNamePlaceholder": "eg. John Doe", "IMAPSetupDialog_DisplayNamePlaceholder": "eg. John Doe",
"IMAPSetupDialog_IncomingMailServer": "Incoming mail server", "IMAPSetupDialog_IncomingMailServer": "Incoming mail server",
"IMAPSetupDialog_IncomingMailServerPort": "Port", "IMAPSetupDialog_IncomingMailServerPort": "Port",
"IMAPSetupDialog_IMAPSettings": "IMAP Server Settings",
"IMAPSetupDialog_SMTPSettings": "SMTP Server Settings",
"IMAPSetupDialog_MailAddress": "Email address", "IMAPSetupDialog_MailAddress": "Email address",
"IMAPSetupDialog_MailAddressPlaceholder": "someone@example.com", "IMAPSetupDialog_MailAddressPlaceholder": "someone@example.com",
"IMAPSetupDialog_OutgoingMailServer": "Outgoing (SMTP) mail server", "IMAPSetupDialog_OutgoingMailServer": "Outgoing (SMTP) mail server",
@@ -455,6 +466,8 @@
"SearchingIn": "Searching in", "SearchingIn": "Searching in",
"SearchPivotName": "Results", "SearchPivotName": "Results",
"SettingConfigureSpecialFolders_Button": "Configure", "SettingConfigureSpecialFolders_Button": "Configure",
"SettingsEditAccountDetails_IMAPConfiguration_Title": "IMAP/SMTP Configuration",
"SettingsEditAccountDetails_IMAPConfiguration_Description": "Change your incoming/outgoing server settings.",
"SettingsAbout_Description": "Learn more about Wino.", "SettingsAbout_Description": "Learn more about Wino.",
"SettingsAbout_Title": "About", "SettingsAbout_Title": "About",
"SettingsAboutGithub_Description": "Go to issue tracker GitHub repository.", "SettingsAboutGithub_Description": "Go to issue tracker GitHub repository.",
@@ -508,7 +521,7 @@
"SettingsCustomTheme_Title": "Custom Theme", "SettingsCustomTheme_Title": "Custom Theme",
"SettingsDeleteAccount_Description": "Delete all e-mails and credentials associated with this account.", "SettingsDeleteAccount_Description": "Delete all e-mails and credentials associated with this account.",
"SettingsDeleteAccount_Title": "Delete this account", "SettingsDeleteAccount_Title": "Delete this account",
"SettingsDeleteProtection_Description": "Should Wino ask you for comfirmation every time you try to permanently delete a mail using Shift + Del keys?", "SettingsDeleteProtection_Description": "Should Wino ask you for confirmation every time you try to permanently delete a mail using Shift + Del keys?",
"SettingsDeleteProtection_Title": "Permanent Delete Protection", "SettingsDeleteProtection_Title": "Permanent Delete Protection",
"SettingsDiagnostics_Description": "For developers", "SettingsDiagnostics_Description": "For developers",
"SettingsDiagnostics_DiagnosticId_Description": "Share this ID with the developers when asked to get help for the issues you experience in Wino Mail.", "SettingsDiagnostics_DiagnosticId_Description": "Share this ID with the developers when asked to get help for the issues you experience in Wino Mail.",
@@ -566,6 +579,8 @@
"SettingsManageAccountSettings_Title": "Manage Account Settings", "SettingsManageAccountSettings_Title": "Manage Account Settings",
"SettingsManageAliases_Description": "See e-mail aliases assigned for this account, update or delete them.", "SettingsManageAliases_Description": "See e-mail aliases assigned for this account, update or delete them.",
"SettingsManageAliases_Title": "Aliases", "SettingsManageAliases_Title": "Aliases",
"SettingsEditAccountDetails_Title": "Edit Account Details",
"SettingsEditAccountDetails_Description": "Change account name, sender name and assign a new color if you like.",
"SettingsManageLink_Description": "Move items to add new link or remove existing link.", "SettingsManageLink_Description": "Move items to add new link or remove existing link.",
"SettingsManageLink_Title": "Manage Link", "SettingsManageLink_Title": "Manage Link",
"SettingsMarkAsRead_Description": "Change what should happen to the selected item.", "SettingsMarkAsRead_Description": "Change what should happen to the selected item.",
@@ -610,6 +625,11 @@
"SettingsShowPreviewText_Title": "Show Preview Text", "SettingsShowPreviewText_Title": "Show Preview Text",
"SettingsShowSenderPictures_Description": "Hide/show the thumbnail sender pictures.", "SettingsShowSenderPictures_Description": "Hide/show the thumbnail sender pictures.",
"SettingsShowSenderPictures_Title": "Show Sender Avatars", "SettingsShowSenderPictures_Title": "Show Sender Avatars",
"SettingsEnableGravatarAvatars_Title": "Gravatar",
"SettingsEnableGravatarAvatars_Description": "Use gravatar (if available) as sender picture",
"SettingsEnableFavicons_Title": "Domain icons (Favicons)",
"SettingsEnableFavicons_Description": "Use domain favicons (if available) as sender picture",
"SettingsMailList_ClearAvatarsCache_Button": "Clear cached avatars",
"SettingsSignature_AddCustomSignature_Button": "Add signature", "SettingsSignature_AddCustomSignature_Button": "Add signature",
"SettingsSignature_AddCustomSignature_Title": "Add custom signature", "SettingsSignature_AddCustomSignature_Title": "Add custom signature",
"SettingsSignature_DeleteSignature_Title": "Delete signature", "SettingsSignature_DeleteSignature_Title": "Delete signature",
@@ -631,6 +651,8 @@
"SettingsThreads_Title": "Conversation Threading", "SettingsThreads_Title": "Conversation Threading",
"SettingsUnlinkAccounts_Description": "Remove the link between accounts. his will not delete your accounts.", "SettingsUnlinkAccounts_Description": "Remove the link between accounts. his will not delete your accounts.",
"SettingsUnlinkAccounts_Title": "Unlink Accounts", "SettingsUnlinkAccounts_Title": "Unlink Accounts",
"SettingsMailRendering_ActionLabels_Title": "Action labels",
"SettingsMailRendering_ActionLabels_Description": "Show action labels.",
"SignatureDeleteDialog_Message": "Are you sure you want to delete \"{0}\" signature?", "SignatureDeleteDialog_Message": "Are you sure you want to delete \"{0}\" signature?",
"SignatureDeleteDialog_Title": "Delete signature", "SignatureDeleteDialog_Title": "Delete signature",
"SignatureEditorDialog_SignatureName_Placeholder": "Name your signature", "SignatureEditorDialog_SignatureName_Placeholder": "Name your signature",
@@ -676,7 +698,9 @@
"WinoUpgradeDescription": "Wino offers 3 accounts to start with for free. If you need more than 3 accounts, please upgrade", "WinoUpgradeDescription": "Wino offers 3 accounts to start with for free. If you need more than 3 accounts, please upgrade",
"WinoUpgradeMessage": "Upgrade to Unlimited Accounts", "WinoUpgradeMessage": "Upgrade to Unlimited Accounts",
"WinoUpgradeRemainingAccountsMessage": "{0} out of {1} free accounts used.", "WinoUpgradeRemainingAccountsMessage": "{0} out of {1} free accounts used.",
"Yesterday": "Yesterday" "Yesterday": "Yesterday",
"SettingsAppPreferences_EmailSyncInterval_Title": "Email sync interval",
"SettingsAppPreferences_EmailSyncInterval_Description": "Automatic email synchronization interval (minutes). This setting will be applied only after restarting Wino Mail."
} }

View File

@@ -6,7 +6,7 @@
"AccountAlias_Disclaimer_SecondLine": "If you want to use aliases for your Outlook or IMAP account, please add them yourself.", "AccountAlias_Disclaimer_SecondLine": "If you want to use aliases for your Outlook or IMAP account, please add them yourself.",
"AccountCacheReset_Title": "Account Cache Reset", "AccountCacheReset_Title": "Account Cache Reset",
"AccountCacheReset_Message": "This account requires full re-sychronization to continue working. Please wait while Wino re-synchronizes your messages...", "AccountCacheReset_Message": "This account requires full re-sychronization to continue working. Please wait while Wino re-synchronizes your messages...",
"AccountContactNameYou": "You", "AccountContactNameYou": "Vy",
"AccountCreationDialog_Completed": "hotovo", "AccountCreationDialog_Completed": "hotovo",
"AccountCreationDialog_FetchingEvents": "Fetching calendar events.", "AccountCreationDialog_FetchingEvents": "Fetching calendar events.",
"AccountCreationDialog_FetchingProfileInformation": "Fetching profile details.", "AccountCreationDialog_FetchingProfileInformation": "Fetching profile details.",
@@ -22,8 +22,12 @@
"AccountPickerDialog_Title": "Vybrat účet", "AccountPickerDialog_Title": "Vybrat účet",
"AccountSettingsDialog_AccountName": "Jméno odesílatele", "AccountSettingsDialog_AccountName": "Jméno odesílatele",
"AccountSettingsDialog_AccountNamePlaceholder": "např. Jan Novák", "AccountSettingsDialog_AccountNamePlaceholder": "např. Jan Novák",
"AccountDetailsPage_Title": "Account info",
"AccountDetailsPage_Description": "Change the name of the account in Wino and set desired sender name.",
"AccountDetailsPage_ColorPicker_Title": "Account color",
"AccountDetailsPage_ColorPicker_Description": "Assign a new account color to colorize its symbol in the list.",
"AddHyperlink": "Přidat", "AddHyperlink": "Přidat",
"AppCloseBackgroundSynchronizationWarningTitle": "Background Synchronization", "AppCloseBackgroundSynchronizationWarningTitle": "Synchronizace na pozadí",
"AppCloseStartupLaunchDisabledWarningMessageFirstLine": "Application has not been set to launch on Windows startup.", "AppCloseStartupLaunchDisabledWarningMessageFirstLine": "Application has not been set to launch on Windows startup.",
"AppCloseStartupLaunchDisabledWarningMessageSecondLine": "This will cause you to miss notifications when you restart your computer.", "AppCloseStartupLaunchDisabledWarningMessageSecondLine": "This will cause you to miss notifications when you restart your computer.",
"AppCloseStartupLaunchDisabledWarningMessageThirdLine": "Do you want to go to App Preferences page to enable it?", "AppCloseStartupLaunchDisabledWarningMessageThirdLine": "Do you want to go to App Preferences page to enable it?",
@@ -44,7 +48,7 @@
"Busy": "Busy", "Busy": "Busy",
"Buttons_AddAccount": "Přidat účet", "Buttons_AddAccount": "Přidat účet",
"Buttons_AddNewAlias": "Add New Alias", "Buttons_AddNewAlias": "Add New Alias",
"Buttons_Allow": "Allow", "Buttons_Allow": "Povolit",
"Buttons_ApplyTheme": "Použít motiv", "Buttons_ApplyTheme": "Použít motiv",
"Buttons_Browse": "Procházet", "Buttons_Browse": "Procházet",
"Buttons_Cancel": "Zrušit", "Buttons_Cancel": "Zrušit",
@@ -68,7 +72,7 @@
"Buttons_Send": "Send", "Buttons_Send": "Send",
"Buttons_Share": "Sdílet", "Buttons_Share": "Sdílet",
"Buttons_SignIn": "Přihlásit se", "Buttons_SignIn": "Přihlásit se",
"Buttons_Sync": "Synchronize", "Buttons_Sync": "Synchronizovat",
"Buttons_SyncAliases": "Synchronize Aliases", "Buttons_SyncAliases": "Synchronize Aliases",
"Buttons_TryAgain": "Zkusit znovu", "Buttons_TryAgain": "Zkusit znovu",
"Buttons_Yes": "Ano", "Buttons_Yes": "Ano",
@@ -95,9 +99,9 @@
"CreateAccountAliasDialog_AliasAddress": "Address", "CreateAccountAliasDialog_AliasAddress": "Address",
"CreateAccountAliasDialog_AliasAddressPlaceholder": "eg. support@mydomain.com", "CreateAccountAliasDialog_AliasAddressPlaceholder": "eg. support@mydomain.com",
"CreateAccountAliasDialog_Description": "Make sure your outgoing server allows sending mails from this alias.", "CreateAccountAliasDialog_Description": "Make sure your outgoing server allows sending mails from this alias.",
"CreateAccountAliasDialog_ReplyToAddress": "Reply-To Address", "CreateAccountAliasDialog_ReplyToAddress": "Odpověď na adresu",
"CreateAccountAliasDialog_ReplyToAddressPlaceholder": "admin@mydomain.com", "CreateAccountAliasDialog_ReplyToAddressPlaceholder": "admin@mydomain.com",
"CreateAccountAliasDialog_Title": "Create Account Alias", "CreateAccountAliasDialog_Title": "Vytvořit Alias účtu",
"CustomThemeBuilder_AccentColorDescription": "Pokud chcete, můžete si nastavit barevný tón. Jinak se použije se výchozí barevný tón Windows.", "CustomThemeBuilder_AccentColorDescription": "Pokud chcete, můžete si nastavit barevný tón. Jinak se použije se výchozí barevný tón Windows.",
"CustomThemeBuilder_AccentColorTitle": "Barevný tón", "CustomThemeBuilder_AccentColorTitle": "Barevný tón",
"CustomThemeBuilder_PickColor": "Vybrat", "CustomThemeBuilder_PickColor": "Vybrat",
@@ -127,7 +131,7 @@
"DialogMessage_DeleteAccountConfirmationTitle": "Všechna data spojená s tímto účtem budou trvale smazána z disku.", "DialogMessage_DeleteAccountConfirmationTitle": "Všechna data spojená s tímto účtem budou trvale smazána z disku.",
"DialogMessage_DiscardDraftConfirmationMessage": "Tento koncept bude zahozen. Chcete pokračovat?", "DialogMessage_DiscardDraftConfirmationMessage": "Tento koncept bude zahozen. Chcete pokračovat?",
"DialogMessage_DiscardDraftConfirmationTitle": "Zahodit koncept", "DialogMessage_DiscardDraftConfirmationTitle": "Zahodit koncept",
"DialogMessage_EmptySubjectConfirmation": "Missing Subject", "DialogMessage_EmptySubjectConfirmation": "Chybějící Předmět",
"DialogMessage_EmptySubjectConfirmationMessage": "Zpráva nemá Předmět. Chcete pokračovat?", "DialogMessage_EmptySubjectConfirmationMessage": "Zpráva nemá Předmět. Chcete pokračovat?",
"DialogMessage_EnableStartupLaunchDeniedMessage": "You can enable startup launch from Settings -> App Preferences.", "DialogMessage_EnableStartupLaunchDeniedMessage": "You can enable startup launch from Settings -> App Preferences.",
"DialogMessage_EnableStartupLaunchMessage": "Let Wino Mail automatically launch minimized on Windows startup to not miss any notifications.\n\nDo you want to enable startup launch?", "DialogMessage_EnableStartupLaunchMessage": "Let Wino Mail automatically launch minimized on Windows startup to not miss any notifications.\n\nDo you want to enable startup launch?",
@@ -256,6 +260,11 @@
"ImapConnectionSecurity_SslTls": "SSL/TLS", "ImapConnectionSecurity_SslTls": "SSL/TLS",
"ImapConnectionSecurity_StartTls": "STARTTLS", "ImapConnectionSecurity_StartTls": "STARTTLS",
"IMAPSetupDialog_AccountType": "Typ účtu", "IMAPSetupDialog_AccountType": "Typ účtu",
"IMAPSetupDialog_ValidationSuccess_Title": "Success",
"IMAPSetupDialog_ValidationSuccess_Message": "Validation successful",
"IMAPSetupDialog_SaveImapSuccess_Title": "Success",
"IMAPSetupDialog_SaveImapSuccess_Message": "IMAP settings saved successfuly.",
"IMAPSetupDialog_ValidationFailed_Title": "IMAP Server validation failed.",
"IMAPSetupDialog_CertificateAllowanceRequired_Row0": "This server is requesting a SSL handshake to continue. Please confirm the certificate details below.", "IMAPSetupDialog_CertificateAllowanceRequired_Row0": "This server is requesting a SSL handshake to continue. Please confirm the certificate details below.",
"IMAPSetupDialog_CertificateAllowanceRequired_Row1": "Allow the handshake to continue setting up your account.", "IMAPSetupDialog_CertificateAllowanceRequired_Row1": "Allow the handshake to continue setting up your account.",
"IMAPSetupDialog_CertificateDenied": "User didn't authorize the handshake with the certificate.", "IMAPSetupDialog_CertificateDenied": "User didn't authorize the handshake with the certificate.",
@@ -270,6 +279,8 @@
"IMAPSetupDialog_DisplayNamePlaceholder": "např. Jan Novák", "IMAPSetupDialog_DisplayNamePlaceholder": "např. Jan Novák",
"IMAPSetupDialog_IncomingMailServer": "Server příchozí pošty", "IMAPSetupDialog_IncomingMailServer": "Server příchozí pošty",
"IMAPSetupDialog_IncomingMailServerPort": "Port", "IMAPSetupDialog_IncomingMailServerPort": "Port",
"IMAPSetupDialog_IMAPSettings": "IMAP Server Settings",
"IMAPSetupDialog_SMTPSettings": "SMTP Server Settings",
"IMAPSetupDialog_MailAddress": "E-mailová adresa", "IMAPSetupDialog_MailAddress": "E-mailová adresa",
"IMAPSetupDialog_MailAddressPlaceholder": "jan.novák@seznam.cz", "IMAPSetupDialog_MailAddressPlaceholder": "jan.novák@seznam.cz",
"IMAPSetupDialog_OutgoingMailServer": "Server odchozí pošty (SMTP)", "IMAPSetupDialog_OutgoingMailServer": "Server odchozí pošty (SMTP)",
@@ -455,6 +466,8 @@
"SearchingIn": "Vyhledávání v", "SearchingIn": "Vyhledávání v",
"SearchPivotName": "Výsledky", "SearchPivotName": "Výsledky",
"SettingConfigureSpecialFolders_Button": "Nastavit", "SettingConfigureSpecialFolders_Button": "Nastavit",
"SettingsEditAccountDetails_IMAPConfiguration_Title": "IMAP/SMTP Configuration",
"SettingsEditAccountDetails_IMAPConfiguration_Description": "Change your incoming/outgoing server settings.",
"SettingsAbout_Description": "Zjistěte více o Wino.", "SettingsAbout_Description": "Zjistěte více o Wino.",
"SettingsAbout_Title": "O aplikaci", "SettingsAbout_Title": "O aplikaci",
"SettingsAboutGithub_Description": "Přejít na seznam chyb na GitHub.", "SettingsAboutGithub_Description": "Přejít na seznam chyb na GitHub.",
@@ -508,7 +521,7 @@
"SettingsCustomTheme_Title": "Vlastní motiv", "SettingsCustomTheme_Title": "Vlastní motiv",
"SettingsDeleteAccount_Description": "Odstranit všechny e-maily a přihlašovací údaje spojené s tímto účtem.", "SettingsDeleteAccount_Description": "Odstranit všechny e-maily a přihlašovací údaje spojené s tímto účtem.",
"SettingsDeleteAccount_Title": "Smazat tento účet", "SettingsDeleteAccount_Title": "Smazat tento účet",
"SettingsDeleteProtection_Description": "Měl by vás Wino požádat o potvrzení pokaždé, když se pokoušíte trvale smazat e-mail pomocí kláves Shift + Del?", "SettingsDeleteProtection_Description": "Should Wino ask you for confirmation every time you try to permanently delete a mail using Shift + Del keys?",
"SettingsDeleteProtection_Title": "Ochrana proti trvalému smazání", "SettingsDeleteProtection_Title": "Ochrana proti trvalému smazání",
"SettingsDiagnostics_Description": "Pro vývojáře", "SettingsDiagnostics_Description": "Pro vývojáře",
"SettingsDiagnostics_DiagnosticId_Description": "Share this ID with the developers when asked to get help for the issues you experience in Wino Mail.", "SettingsDiagnostics_DiagnosticId_Description": "Share this ID with the developers when asked to get help for the issues you experience in Wino Mail.",
@@ -566,6 +579,8 @@
"SettingsManageAccountSettings_Title": "Správa nastavení účtů", "SettingsManageAccountSettings_Title": "Správa nastavení účtů",
"SettingsManageAliases_Description": "See e-mail aliases assigned for this account, update or delete them.", "SettingsManageAliases_Description": "See e-mail aliases assigned for this account, update or delete them.",
"SettingsManageAliases_Title": "Aliases", "SettingsManageAliases_Title": "Aliases",
"SettingsEditAccountDetails_Title": "Edit Account Details",
"SettingsEditAccountDetails_Description": "Change account name, sender name and assign a new color if you like.",
"SettingsManageLink_Description": "Přesunout položky pro přidání nového propojení účtů nebo odstranění již existujícího.", "SettingsManageLink_Description": "Přesunout položky pro přidání nového propojení účtů nebo odstranění již existujícího.",
"SettingsManageLink_Title": "Spravovat propojení", "SettingsManageLink_Title": "Spravovat propojení",
"SettingsMarkAsRead_Description": "Změnit, co by se mělo stát s vybranou položkou.", "SettingsMarkAsRead_Description": "Změnit, co by se mělo stát s vybranou položkou.",
@@ -610,6 +625,11 @@
"SettingsShowPreviewText_Title": "Zobrazit náhled textu", "SettingsShowPreviewText_Title": "Zobrazit náhled textu",
"SettingsShowSenderPictures_Description": "Skrýt/zobrazit náhled obrázku odesílatele.", "SettingsShowSenderPictures_Description": "Skrýt/zobrazit náhled obrázku odesílatele.",
"SettingsShowSenderPictures_Title": "Zobrazit avatary odesílatele", "SettingsShowSenderPictures_Title": "Zobrazit avatary odesílatele",
"SettingsEnableGravatarAvatars_Title": "Gravatar",
"SettingsEnableGravatarAvatars_Description": "Use gravatar (if available) as sender picture",
"SettingsEnableFavicons_Title": "Domain icons (Favicons)",
"SettingsEnableFavicons_Description": "Use domain favicons (if available) as sender picture",
"SettingsMailList_ClearAvatarsCache_Button": "Clear cached avatars",
"SettingsSignature_AddCustomSignature_Button": "Add signature", "SettingsSignature_AddCustomSignature_Button": "Add signature",
"SettingsSignature_AddCustomSignature_Title": "Add custom signature", "SettingsSignature_AddCustomSignature_Title": "Add custom signature",
"SettingsSignature_DeleteSignature_Title": "Delete signature", "SettingsSignature_DeleteSignature_Title": "Delete signature",
@@ -631,6 +651,8 @@
"SettingsThreads_Title": "Vlákna konverzací", "SettingsThreads_Title": "Vlákna konverzací",
"SettingsUnlinkAccounts_Description": "Remove the link between accounts. his will not delete your accounts.", "SettingsUnlinkAccounts_Description": "Remove the link between accounts. his will not delete your accounts.",
"SettingsUnlinkAccounts_Title": "Rozpojit účty", "SettingsUnlinkAccounts_Title": "Rozpojit účty",
"SettingsMailRendering_ActionLabels_Title": "Action labels",
"SettingsMailRendering_ActionLabels_Description": "Show action labels.",
"SignatureDeleteDialog_Message": "Are you sure you want to delete \"{0}\" signature?", "SignatureDeleteDialog_Message": "Are you sure you want to delete \"{0}\" signature?",
"SignatureDeleteDialog_Title": "Delete signature", "SignatureDeleteDialog_Title": "Delete signature",
"SignatureEditorDialog_SignatureName_Placeholder": "Name your signature", "SignatureEditorDialog_SignatureName_Placeholder": "Name your signature",
@@ -676,7 +698,9 @@
"WinoUpgradeDescription": "Wino nabízí 3 účty zdarma. Pokud potřebujete více než 3 účty, upgradujte prosím.", "WinoUpgradeDescription": "Wino nabízí 3 účty zdarma. Pokud potřebujete více než 3 účty, upgradujte prosím.",
"WinoUpgradeMessage": "Přejít na neomezený počet účtů", "WinoUpgradeMessage": "Přejít na neomezený počet účtů",
"WinoUpgradeRemainingAccountsMessage": "{0} z {1} použitých bezplatných účtů.", "WinoUpgradeRemainingAccountsMessage": "{0} z {1} použitých bezplatných účtů.",
"Yesterday": "Včera" "Yesterday": "Včera",
"SettingsAppPreferences_EmailSyncInterval_Title": "Email sync interval",
"SettingsAppPreferences_EmailSyncInterval_Description": "Automatic email synchronization interval (minutes). This setting will be applied only after restarting Wino Mail."
} }

View File

@@ -22,6 +22,10 @@
"AccountPickerDialog_Title": "Pick an account", "AccountPickerDialog_Title": "Pick an account",
"AccountSettingsDialog_AccountName": "Sender Display Name", "AccountSettingsDialog_AccountName": "Sender Display Name",
"AccountSettingsDialog_AccountNamePlaceholder": "eg. John Doe", "AccountSettingsDialog_AccountNamePlaceholder": "eg. John Doe",
"AccountDetailsPage_Title": "Account info",
"AccountDetailsPage_Description": "Change the name of the account in Wino and set desired sender name.",
"AccountDetailsPage_ColorPicker_Title": "Account color",
"AccountDetailsPage_ColorPicker_Description": "Assign a new account color to colorize its symbol in the list.",
"AddHyperlink": "Add", "AddHyperlink": "Add",
"AppCloseBackgroundSynchronizationWarningTitle": "Background Synchronization", "AppCloseBackgroundSynchronizationWarningTitle": "Background Synchronization",
"AppCloseStartupLaunchDisabledWarningMessageFirstLine": "Application has not been set to launch on Windows startup.", "AppCloseStartupLaunchDisabledWarningMessageFirstLine": "Application has not been set to launch on Windows startup.",
@@ -256,6 +260,11 @@
"ImapConnectionSecurity_SslTls": "SSL/TLS", "ImapConnectionSecurity_SslTls": "SSL/TLS",
"ImapConnectionSecurity_StartTls": "STARTTLS", "ImapConnectionSecurity_StartTls": "STARTTLS",
"IMAPSetupDialog_AccountType": "Account type", "IMAPSetupDialog_AccountType": "Account type",
"IMAPSetupDialog_ValidationSuccess_Title": "Success",
"IMAPSetupDialog_ValidationSuccess_Message": "Validation successful",
"IMAPSetupDialog_SaveImapSuccess_Title": "Success",
"IMAPSetupDialog_SaveImapSuccess_Message": "IMAP settings saved successfuly.",
"IMAPSetupDialog_ValidationFailed_Title": "IMAP Server validation failed.",
"IMAPSetupDialog_CertificateAllowanceRequired_Row0": "This server is requesting a SSL handshake to continue. Please confirm the certificate details below.", "IMAPSetupDialog_CertificateAllowanceRequired_Row0": "This server is requesting a SSL handshake to continue. Please confirm the certificate details below.",
"IMAPSetupDialog_CertificateAllowanceRequired_Row1": "Allow the handshake to continue setting up your account.", "IMAPSetupDialog_CertificateAllowanceRequired_Row1": "Allow the handshake to continue setting up your account.",
"IMAPSetupDialog_CertificateDenied": "User didn't authorize the handshake with the certificate.", "IMAPSetupDialog_CertificateDenied": "User didn't authorize the handshake with the certificate.",
@@ -270,6 +279,8 @@
"IMAPSetupDialog_DisplayNamePlaceholder": "eg. John Doe", "IMAPSetupDialog_DisplayNamePlaceholder": "eg. John Doe",
"IMAPSetupDialog_IncomingMailServer": "Incoming mail server", "IMAPSetupDialog_IncomingMailServer": "Incoming mail server",
"IMAPSetupDialog_IncomingMailServerPort": "Port", "IMAPSetupDialog_IncomingMailServerPort": "Port",
"IMAPSetupDialog_IMAPSettings": "IMAP Server Settings",
"IMAPSetupDialog_SMTPSettings": "SMTP Server Settings",
"IMAPSetupDialog_MailAddress": "Email address", "IMAPSetupDialog_MailAddress": "Email address",
"IMAPSetupDialog_MailAddressPlaceholder": "someone@example.com", "IMAPSetupDialog_MailAddressPlaceholder": "someone@example.com",
"IMAPSetupDialog_OutgoingMailServer": "Outgoing (SMTP) mail server", "IMAPSetupDialog_OutgoingMailServer": "Outgoing (SMTP) mail server",
@@ -455,6 +466,8 @@
"SearchingIn": "Searching in", "SearchingIn": "Searching in",
"SearchPivotName": "Results", "SearchPivotName": "Results",
"SettingConfigureSpecialFolders_Button": "Configure", "SettingConfigureSpecialFolders_Button": "Configure",
"SettingsEditAccountDetails_IMAPConfiguration_Title": "IMAP/SMTP Configuration",
"SettingsEditAccountDetails_IMAPConfiguration_Description": "Change your incoming/outgoing server settings.",
"SettingsAbout_Description": "Learn more about Wino.", "SettingsAbout_Description": "Learn more about Wino.",
"SettingsAbout_Title": "About", "SettingsAbout_Title": "About",
"SettingsAboutGithub_Description": "Go to issue tracker GitHub repository.", "SettingsAboutGithub_Description": "Go to issue tracker GitHub repository.",
@@ -508,7 +521,7 @@
"SettingsCustomTheme_Title": "Custom Theme", "SettingsCustomTheme_Title": "Custom Theme",
"SettingsDeleteAccount_Description": "Delete all e-mails and credentials associated with this account.", "SettingsDeleteAccount_Description": "Delete all e-mails and credentials associated with this account.",
"SettingsDeleteAccount_Title": "Delete this account", "SettingsDeleteAccount_Title": "Delete this account",
"SettingsDeleteProtection_Description": "Should Wino ask you for comfirmation every time you try to permanently delete a mail using Shift + Del keys?", "SettingsDeleteProtection_Description": "Should Wino ask you for confirmation every time you try to permanently delete a mail using Shift + Del keys?",
"SettingsDeleteProtection_Title": "Permanent Delete Protection", "SettingsDeleteProtection_Title": "Permanent Delete Protection",
"SettingsDiagnostics_Description": "For developers", "SettingsDiagnostics_Description": "For developers",
"SettingsDiagnostics_DiagnosticId_Description": "Share this ID with the developers when asked to get help for the issues you experience in Wino Mail.", "SettingsDiagnostics_DiagnosticId_Description": "Share this ID with the developers when asked to get help for the issues you experience in Wino Mail.",
@@ -566,6 +579,8 @@
"SettingsManageAccountSettings_Title": "Manage Account Settings", "SettingsManageAccountSettings_Title": "Manage Account Settings",
"SettingsManageAliases_Description": "See e-mail aliases assigned for this account, update or delete them.", "SettingsManageAliases_Description": "See e-mail aliases assigned for this account, update or delete them.",
"SettingsManageAliases_Title": "Aliases", "SettingsManageAliases_Title": "Aliases",
"SettingsEditAccountDetails_Title": "Edit Account Details",
"SettingsEditAccountDetails_Description": "Change account name, sender name and assign a new color if you like.",
"SettingsManageLink_Description": "Move items to add new link or remove existing link.", "SettingsManageLink_Description": "Move items to add new link or remove existing link.",
"SettingsManageLink_Title": "Manage Link", "SettingsManageLink_Title": "Manage Link",
"SettingsMarkAsRead_Description": "Change what should happen to the selected item.", "SettingsMarkAsRead_Description": "Change what should happen to the selected item.",
@@ -610,6 +625,11 @@
"SettingsShowPreviewText_Title": "Show Preview Text", "SettingsShowPreviewText_Title": "Show Preview Text",
"SettingsShowSenderPictures_Description": "Hide/show the thumbnail sender pictures.", "SettingsShowSenderPictures_Description": "Hide/show the thumbnail sender pictures.",
"SettingsShowSenderPictures_Title": "Show Sender Avatars", "SettingsShowSenderPictures_Title": "Show Sender Avatars",
"SettingsEnableGravatarAvatars_Title": "Gravatar",
"SettingsEnableGravatarAvatars_Description": "Use gravatar (if available) as sender picture",
"SettingsEnableFavicons_Title": "Domain icons (Favicons)",
"SettingsEnableFavicons_Description": "Use domain favicons (if available) as sender picture",
"SettingsMailList_ClearAvatarsCache_Button": "Clear cached avatars",
"SettingsSignature_AddCustomSignature_Button": "Add signature", "SettingsSignature_AddCustomSignature_Button": "Add signature",
"SettingsSignature_AddCustomSignature_Title": "Add custom signature", "SettingsSignature_AddCustomSignature_Title": "Add custom signature",
"SettingsSignature_DeleteSignature_Title": "Delete signature", "SettingsSignature_DeleteSignature_Title": "Delete signature",
@@ -631,6 +651,8 @@
"SettingsThreads_Title": "Conversation Threading", "SettingsThreads_Title": "Conversation Threading",
"SettingsUnlinkAccounts_Description": "Remove the link between accounts. his will not delete your accounts.", "SettingsUnlinkAccounts_Description": "Remove the link between accounts. his will not delete your accounts.",
"SettingsUnlinkAccounts_Title": "Unlink Accounts", "SettingsUnlinkAccounts_Title": "Unlink Accounts",
"SettingsMailRendering_ActionLabels_Title": "Action labels",
"SettingsMailRendering_ActionLabels_Description": "Show action labels.",
"SignatureDeleteDialog_Message": "Are you sure you want to delete \"{0}\" signature?", "SignatureDeleteDialog_Message": "Are you sure you want to delete \"{0}\" signature?",
"SignatureDeleteDialog_Title": "Delete signature", "SignatureDeleteDialog_Title": "Delete signature",
"SignatureEditorDialog_SignatureName_Placeholder": "Name your signature", "SignatureEditorDialog_SignatureName_Placeholder": "Name your signature",
@@ -676,7 +698,9 @@
"WinoUpgradeDescription": "Wino offers 3 accounts to start with for free. If you need more than 3 accounts, please upgrade", "WinoUpgradeDescription": "Wino offers 3 accounts to start with for free. If you need more than 3 accounts, please upgrade",
"WinoUpgradeMessage": "Upgrade to Unlimited Accounts", "WinoUpgradeMessage": "Upgrade to Unlimited Accounts",
"WinoUpgradeRemainingAccountsMessage": "{0} out of {1} free accounts used.", "WinoUpgradeRemainingAccountsMessage": "{0} out of {1} free accounts used.",
"Yesterday": "Yesterday" "Yesterday": "Yesterday",
"SettingsAppPreferences_EmailSyncInterval_Title": "Email sync interval",
"SettingsAppPreferences_EmailSyncInterval_Description": "Automatic email synchronization interval (minutes). This setting will be applied only after restarting Wino Mail."
} }

View File

@@ -4,8 +4,8 @@
"AccountAlias_Column_Verified": "Verifiziert", "AccountAlias_Column_Verified": "Verifiziert",
"AccountAlias_Disclaimer_FirstLine": "Wino kann nur Aliase für Ihre Gmail-Konten importieren.", "AccountAlias_Disclaimer_FirstLine": "Wino kann nur Aliase für Ihre Gmail-Konten importieren.",
"AccountAlias_Disclaimer_SecondLine": "Wenn Sie Aliase für Ihr Outlook- oder IMAP-Konto verwenden möchten, fügen Sie diese bitte selbst hinzu.", "AccountAlias_Disclaimer_SecondLine": "Wenn Sie Aliase für Ihr Outlook- oder IMAP-Konto verwenden möchten, fügen Sie diese bitte selbst hinzu.",
"AccountCacheReset_Title": "Account Cache Reset", "AccountCacheReset_Title": "Account-Cache zurücksetzen",
"AccountCacheReset_Message": "This account requires full re-sychronization to continue working. Please wait while Wino re-synchronizes your messages...", "AccountCacheReset_Message": "Dieser Account erfordert eine vollständige Neu-Sychronisierung, um fortzufahren. Bitte warten Sie, während Wino Ihre Nachrichten erneut synchronisiert...",
"AccountContactNameYou": "Sie", "AccountContactNameYou": "Sie",
"AccountCreationDialog_Completed": "alles erledigt", "AccountCreationDialog_Completed": "alles erledigt",
"AccountCreationDialog_FetchingEvents": "Kalenderereignisse werden abgerufen.", "AccountCreationDialog_FetchingEvents": "Kalenderereignisse werden abgerufen.",
@@ -22,6 +22,10 @@
"AccountPickerDialog_Title": "Konto auswählen", "AccountPickerDialog_Title": "Konto auswählen",
"AccountSettingsDialog_AccountName": "Absender-Anzeigename", "AccountSettingsDialog_AccountName": "Absender-Anzeigename",
"AccountSettingsDialog_AccountNamePlaceholder": "z.B. Max Mustermann", "AccountSettingsDialog_AccountNamePlaceholder": "z.B. Max Mustermann",
"AccountDetailsPage_Title": "Konto-Info",
"AccountDetailsPage_Description": "Ändern Sie den Namen des Kontos in Wino und setzen Sie den gewünschten Absendernamen.",
"AccountDetailsPage_ColorPicker_Title": "Konto-Farbe",
"AccountDetailsPage_ColorPicker_Description": "Zuweisen einer neuen Kontofarbe, um das Symbol in der Liste einzufärben.",
"AddHyperlink": "Hinzufügen", "AddHyperlink": "Hinzufügen",
"AppCloseBackgroundSynchronizationWarningTitle": "Hintergrundsynchronisierung", "AppCloseBackgroundSynchronizationWarningTitle": "Hintergrundsynchronisierung",
"AppCloseStartupLaunchDisabledWarningMessageFirstLine": "Die Anwendung wird beim Start von Windows nicht gestartet.", "AppCloseStartupLaunchDisabledWarningMessageFirstLine": "Die Anwendung wird beim Start von Windows nicht gestartet.",
@@ -184,7 +188,7 @@
"Exception_ImapClientPoolFailed": "IMAP Client-Pool fehlgeschlagen.", "Exception_ImapClientPoolFailed": "IMAP Client-Pool fehlgeschlagen.",
"Exception_InboxNotAvailable": "Konto-Ordner konnten nicht eingerichtet werden.", "Exception_InboxNotAvailable": "Konto-Ordner konnten nicht eingerichtet werden.",
"Exception_InvalidSystemFolderConfiguration": "Die Konfiguration des Systemordners ist nicht gültig. Überprüfen Sie die Konfiguration und versuchen Sie es erneut.", "Exception_InvalidSystemFolderConfiguration": "Die Konfiguration des Systemordners ist nicht gültig. Überprüfen Sie die Konfiguration und versuchen Sie es erneut.",
"Exception_InvalidMultiAccountMoveTarget": "You can't move multiple items that belong to different accounts in linked account.", "Exception_InvalidMultiAccountMoveTarget": "Sie können nicht mehrere Elemente, die zu verschiedenen Konten gehören, in verknüpften Konten verschieben.",
"Exception_MailProcessing": "Diese Mail wird noch verarbeitet. Bitte versuchen Sie es in wenigen Sekunden erneut.", "Exception_MailProcessing": "Diese Mail wird noch verarbeitet. Bitte versuchen Sie es in wenigen Sekunden erneut.",
"Exception_MissingAlias": "Der primäre Alias fehlt für dieses Konto. Erstellen des Entwurfs fehlgeschlagen.", "Exception_MissingAlias": "Der primäre Alias fehlt für dieses Konto. Erstellen des Entwurfs fehlgeschlagen.",
"Exception_NullAssignedAccount": "Zugewiesenes Konto ist 'null'", "Exception_NullAssignedAccount": "Zugewiesenes Konto ist 'null'",
@@ -217,9 +221,9 @@
"GeneralTitle_Error": "Fehler", "GeneralTitle_Error": "Fehler",
"GeneralTitle_Info": "Information", "GeneralTitle_Info": "Information",
"GeneralTitle_Warning": "Warnung", "GeneralTitle_Warning": "Warnung",
"GmailServiceDisabled_Title": "Gmail Error", "GmailServiceDisabled_Title": "Google Mail-Fehler",
"GmailServiceDisabled_Message": "Your Google Workspace account seems to be disabled for Gmail service. Please contact your administrator to enable Gmail service for your account.", "GmailServiceDisabled_Message": "Ihr Google Workspace-Konto scheint für den Google Mail-Dienst deaktiviert zu sein. Bitte kontaktieren Sie Ihren Administrator, um den Google Mail-Dienst für Ihr Konto zu aktivieren.",
"GmailArchiveFolderNameOverride": "Archive", "GmailArchiveFolderNameOverride": "Archivieren",
"HoverActionOption_Archive": "Archivieren", "HoverActionOption_Archive": "Archivieren",
"HoverActionOption_Delete": "Löschen", "HoverActionOption_Delete": "Löschen",
"HoverActionOption_MoveJunk": "In den Papierkorb verschieben", "HoverActionOption_MoveJunk": "In den Papierkorb verschieben",
@@ -228,22 +232,22 @@
"ImageRenderingDisabled": "Bilddarstellung ist für diese Nachricht deaktiviert.", "ImageRenderingDisabled": "Bilddarstellung ist für diese Nachricht deaktiviert.",
"ImapAdvancedSetupDialog_AuthenticationMethod": "Authentifizierungsmethode", "ImapAdvancedSetupDialog_AuthenticationMethod": "Authentifizierungsmethode",
"ImapAdvancedSetupDialog_ConnectionSecurity": "Verbindungssicherheit", "ImapAdvancedSetupDialog_ConnectionSecurity": "Verbindungssicherheit",
"IMAPAdvancedSetupDialog_ValidationAuthMethodRequired": "Authentication method is required", "IMAPAdvancedSetupDialog_ValidationAuthMethodRequired": "Authentifizierungsmethode ist erforderlich",
"IMAPAdvancedSetupDialog_ValidationConnectionSecurityRequired": "Connection security type is required", "IMAPAdvancedSetupDialog_ValidationConnectionSecurityRequired": "Verbindungstyp ist erforderlich",
"IMAPAdvancedSetupDialog_ValidationDisplayNameRequired": "Display name is required", "IMAPAdvancedSetupDialog_ValidationDisplayNameRequired": "Anzeigename ist erforderlich",
"IMAPAdvancedSetupDialog_ValidationEmailInvalid": "Please enter a valid email address", "IMAPAdvancedSetupDialog_ValidationEmailInvalid": "Bitte geben Sie eine gültige E-Mail-Adresse ein",
"IMAPAdvancedSetupDialog_ValidationEmailRequired": "Email address is required", "IMAPAdvancedSetupDialog_ValidationEmailRequired": "E-Mail-Adresse ist erforderlich",
"IMAPAdvancedSetupDialog_ValidationErrorTitle": "Please check the following:", "IMAPAdvancedSetupDialog_ValidationErrorTitle": "Bitte überprüfen Sie das Folgende:",
"IMAPAdvancedSetupDialog_ValidationIncomingPortInvalid": "Incoming port must be between 1-65535", "IMAPAdvancedSetupDialog_ValidationIncomingPortInvalid": "Eingehender Port muss zwischen 1 und 65535 liegen",
"IMAPAdvancedSetupDialog_ValidationIncomingPortRequired": "Incoming server port is required", "IMAPAdvancedSetupDialog_ValidationIncomingPortRequired": "Eingehender Server-Port ist erforderlich",
"IMAPAdvancedSetupDialog_ValidationIncomingServerRequired": "Incoming server address is required", "IMAPAdvancedSetupDialog_ValidationIncomingServerRequired": "Eingehende Server-Adresse ist erforderlich",
"IMAPAdvancedSetupDialog_ValidationOutgoingPasswordRequired": "Outgoing server password is required", "IMAPAdvancedSetupDialog_ValidationOutgoingPasswordRequired": "Ausgehendes Server-Passwort ist erforderlich",
"IMAPAdvancedSetupDialog_ValidationOutgoingPortInvalid": "Outgoing port must be between 1-65535", "IMAPAdvancedSetupDialog_ValidationOutgoingPortInvalid": "Ausgehender Port muss zwischen 1 und 65535 liegen",
"IMAPAdvancedSetupDialog_ValidationOutgoingPortRequired": "Outgoing server port is required", "IMAPAdvancedSetupDialog_ValidationOutgoingPortRequired": "Ausgehender Server-Port ist erforderlich",
"IMAPAdvancedSetupDialog_ValidationOutgoingServerRequired": "Outgoing server address is required", "IMAPAdvancedSetupDialog_ValidationOutgoingServerRequired": "Ausgehende Server-Adresse ist erforderlich",
"IMAPAdvancedSetupDialog_ValidationOutgoingUsernameRequired": "Outgoing server username is required", "IMAPAdvancedSetupDialog_ValidationOutgoingUsernameRequired": "Ausgehender Server-Benutzername ist erforderlich",
"IMAPAdvancedSetupDialog_ValidationPasswordRequired": "Password is required", "IMAPAdvancedSetupDialog_ValidationPasswordRequired": "Passwort ist erforderlich",
"IMAPAdvancedSetupDialog_ValidationUsernameRequired": "Username is required", "IMAPAdvancedSetupDialog_ValidationUsernameRequired": "Benutzername ist erforderlich",
"ImapAuthenticationMethod_Auto": "Auto", "ImapAuthenticationMethod_Auto": "Auto",
"ImapAuthenticationMethod_CramMD5": "CRAM-MD5", "ImapAuthenticationMethod_CramMD5": "CRAM-MD5",
"ImapAuthenticationMethod_DigestMD5": "DIGEST-MD5", "ImapAuthenticationMethod_DigestMD5": "DIGEST-MD5",
@@ -256,6 +260,11 @@
"ImapConnectionSecurity_SslTls": "SSL/TLS", "ImapConnectionSecurity_SslTls": "SSL/TLS",
"ImapConnectionSecurity_StartTls": "STARTTLS", "ImapConnectionSecurity_StartTls": "STARTTLS",
"IMAPSetupDialog_AccountType": "Kontotyp", "IMAPSetupDialog_AccountType": "Kontotyp",
"IMAPSetupDialog_ValidationSuccess_Title": "Erfolgreich",
"IMAPSetupDialog_ValidationSuccess_Message": "Validierung erfolgreich",
"IMAPSetupDialog_SaveImapSuccess_Title": "Erfolg",
"IMAPSetupDialog_SaveImapSuccess_Message": "IMAP-Einstellungen erfolgreich gespeichert.",
"IMAPSetupDialog_ValidationFailed_Title": "IMAP-Server-Validierung fehlgeschlagen.",
"IMAPSetupDialog_CertificateAllowanceRequired_Row0": "Dieser Server fordert einen SSL-Handshake an, um fortzufahren. Bitte bestätigen Sie die Details des Zertifikats unten.", "IMAPSetupDialog_CertificateAllowanceRequired_Row0": "Dieser Server fordert einen SSL-Handshake an, um fortzufahren. Bitte bestätigen Sie die Details des Zertifikats unten.",
"IMAPSetupDialog_CertificateAllowanceRequired_Row1": "Erlaube dem Handshake, die Einrichtung deines Kontos fortzusetzen.", "IMAPSetupDialog_CertificateAllowanceRequired_Row1": "Erlaube dem Handshake, die Einrichtung deines Kontos fortzusetzen.",
"IMAPSetupDialog_CertificateDenied": "Der Benutzer hat den Handshake mit dem Zertifikat nicht autorisiert.", "IMAPSetupDialog_CertificateDenied": "Der Benutzer hat den Handshake mit dem Zertifikat nicht autorisiert.",
@@ -270,6 +279,8 @@
"IMAPSetupDialog_DisplayNamePlaceholder": "z.B. John Doe", "IMAPSetupDialog_DisplayNamePlaceholder": "z.B. John Doe",
"IMAPSetupDialog_IncomingMailServer": "Eingehender Mail-Server", "IMAPSetupDialog_IncomingMailServer": "Eingehender Mail-Server",
"IMAPSetupDialog_IncomingMailServerPort": "Port", "IMAPSetupDialog_IncomingMailServerPort": "Port",
"IMAPSetupDialog_IMAPSettings": "IMAP-Server-Einstellungen",
"IMAPSetupDialog_SMTPSettings": "SMTP-Server-Einstellungen",
"IMAPSetupDialog_MailAddress": "E-Mail Adresse", "IMAPSetupDialog_MailAddress": "E-Mail Adresse",
"IMAPSetupDialog_MailAddressPlaceholder": "jemand@beispiel.de", "IMAPSetupDialog_MailAddressPlaceholder": "jemand@beispiel.de",
"IMAPSetupDialog_OutgoingMailServer": "Ausgehender (SMTP) Mail-Server", "IMAPSetupDialog_OutgoingMailServer": "Ausgehender (SMTP) Mail-Server",
@@ -455,6 +466,8 @@
"SearchingIn": "Suche in", "SearchingIn": "Suche in",
"SearchPivotName": "Ergebnisse", "SearchPivotName": "Ergebnisse",
"SettingConfigureSpecialFolders_Button": "Konfigurieren", "SettingConfigureSpecialFolders_Button": "Konfigurieren",
"SettingsEditAccountDetails_IMAPConfiguration_Title": "IMAP/SMTP-Konfiguration",
"SettingsEditAccountDetails_IMAPConfiguration_Description": "Ändern Sie Ihre eingehenden/ausgehenden Servereinstellungen.",
"SettingsAbout_Description": "Erfahren Sie mehr über Wino.", "SettingsAbout_Description": "Erfahren Sie mehr über Wino.",
"SettingsAbout_Title": "Über", "SettingsAbout_Title": "Über",
"SettingsAboutGithub_Description": "Gehen Sie zum Problem-Tracker GitHub-Repository.", "SettingsAboutGithub_Description": "Gehen Sie zum Problem-Tracker GitHub-Repository.",
@@ -473,10 +486,10 @@
"SettingsAppPreferences_CloseBehavior_Description": "Was soll passieren, wenn Sie die App schließen?", "SettingsAppPreferences_CloseBehavior_Description": "Was soll passieren, wenn Sie die App schließen?",
"SettingsAppPreferences_CloseBehavior_Title": "Verhalten der App beim Schließen", "SettingsAppPreferences_CloseBehavior_Title": "Verhalten der App beim Schließen",
"SettingsAppPreferences_Description": "Allgemeine Einstellungen / Präferenzen für Wino Mail.", "SettingsAppPreferences_Description": "Allgemeine Einstellungen / Präferenzen für Wino Mail.",
"SettingsAppPreferences_SearchMode_Description": "Set whether Wino should check fetched mails first while doing a search or ask your mail server online. Local search is always faster and you can always do an online search if your mail is not in the results.", "SettingsAppPreferences_SearchMode_Description": "Legen Sie fest, ob Wino abgerufene Mails zuerst überprüfen soll, während Sie eine Suche durchführen oder Ihren Mail-Server online fragen. Lokale Suche ist immer schneller und Sie können immer eine Online-Suche durchführen, wenn Ihre E-Mail nicht in den Ergebnissen ist.",
"SettingsAppPreferences_SearchMode_Local": "Local", "SettingsAppPreferences_SearchMode_Local": "Lokal",
"SettingsAppPreferences_SearchMode_Online": "Online", "SettingsAppPreferences_SearchMode_Online": "Online",
"SettingsAppPreferences_SearchMode_Title": "Default search mode", "SettingsAppPreferences_SearchMode_Title": "Standard-Suchmodus",
"SettingsAppPreferences_ServerBackgroundingMode_Invisible_Description": "Wino Mail wird weiterhin im Hintergrund ausgeführt. Sie werden benachrichtigt, sobald neue Mails eintreffen.", "SettingsAppPreferences_ServerBackgroundingMode_Invisible_Description": "Wino Mail wird weiterhin im Hintergrund ausgeführt. Sie werden benachrichtigt, sobald neue Mails eintreffen.",
"SettingsAppPreferences_ServerBackgroundingMode_Invisible_Title": "Im Hintergrund ausführen", "SettingsAppPreferences_ServerBackgroundingMode_Invisible_Title": "Im Hintergrund ausführen",
"SettingsAppPreferences_ServerBackgroundingMode_MinimizeTray_Description": "Wino Mail wird weiterhin im System-Tray laufen. Startet beim Klicken des Symbols die Anwendung. Sie werden benachrichtigt, sobald neue Mails eintreffen.", "SettingsAppPreferences_ServerBackgroundingMode_MinimizeTray_Description": "Wino Mail wird weiterhin im System-Tray laufen. Startet beim Klicken des Symbols die Anwendung. Sie werden benachrichtigt, sobald neue Mails eintreffen.",
@@ -511,8 +524,8 @@
"SettingsDeleteProtection_Description": "Sollte Wino jedes Mal nachfragen, wenn Sie eine Mail mit Umschalten + Entfernen permanent löschen möchten?", "SettingsDeleteProtection_Description": "Sollte Wino jedes Mal nachfragen, wenn Sie eine Mail mit Umschalten + Entfernen permanent löschen möchten?",
"SettingsDeleteProtection_Title": "Schutz vor permanenter Löschung", "SettingsDeleteProtection_Title": "Schutz vor permanenter Löschung",
"SettingsDiagnostics_Description": "Für Entwickler", "SettingsDiagnostics_Description": "Für Entwickler",
"SettingsDiagnostics_DiagnosticId_Description": "Share this ID with the developers when asked to get help for the issues you experience in Wino Mail.", "SettingsDiagnostics_DiagnosticId_Description": "Teilen Sie diese ID mit den Entwicklern, wenn Sie um Hilfe bei Problemen in Wino Mail gebeten werden.",
"SettingsDiagnostics_DiagnosticId_Title": "Diagnostic ID", "SettingsDiagnostics_DiagnosticId_Title": "Diagnose-ID",
"SettingsDiagnostics_Title": "Diagnostik", "SettingsDiagnostics_Title": "Diagnostik",
"SettingsDiscord_Description": "Bekommen Sie reguläre Entwicklungs-Updates, treten Sie Zeitplan-Diskussionen bei und geben Sie Feedback.", "SettingsDiscord_Description": "Bekommen Sie reguläre Entwicklungs-Updates, treten Sie Zeitplan-Diskussionen bei und geben Sie Feedback.",
"SettingsDiscord_Title": "Discord Kanal", "SettingsDiscord_Title": "Discord Kanal",
@@ -566,6 +579,8 @@
"SettingsManageAccountSettings_Title": "Kontoeinstellungen verwalten", "SettingsManageAccountSettings_Title": "Kontoeinstellungen verwalten",
"SettingsManageAliases_Description": "Sehen Sie die Mail-Aliase, die diesem Konto zugewiesen wurden, aktualisieren oder löschen Sie diese.", "SettingsManageAliases_Description": "Sehen Sie die Mail-Aliase, die diesem Konto zugewiesen wurden, aktualisieren oder löschen Sie diese.",
"SettingsManageAliases_Title": "Aliase", "SettingsManageAliases_Title": "Aliase",
"SettingsEditAccountDetails_Title": "Kontodaten bearbeiten",
"SettingsEditAccountDetails_Description": "Ändern Sie den Kontonamen, Absendernamen und weisen Sie eine neue Farbe zu.",
"SettingsManageLink_Description": "Elemente verschieben, um neuen Link hinzuzufügen oder bestehenden Link zu entfernen.", "SettingsManageLink_Description": "Elemente verschieben, um neuen Link hinzuzufügen oder bestehenden Link zu entfernen.",
"SettingsManageLink_Title": "Link verwalten", "SettingsManageLink_Title": "Link verwalten",
"SettingsMarkAsRead_Description": "Ändern Sie, was mit dem ausgewählten Element passieren soll.", "SettingsMarkAsRead_Description": "Ändern Sie, was mit dem ausgewählten Element passieren soll.",
@@ -610,6 +625,11 @@
"SettingsShowPreviewText_Title": "Vorschautext anzeigen", "SettingsShowPreviewText_Title": "Vorschautext anzeigen",
"SettingsShowSenderPictures_Description": "Absender-Profilbilder ausblenden/anzeigen.", "SettingsShowSenderPictures_Description": "Absender-Profilbilder ausblenden/anzeigen.",
"SettingsShowSenderPictures_Title": "Absender-Profilbilder anzeigen", "SettingsShowSenderPictures_Title": "Absender-Profilbilder anzeigen",
"SettingsEnableGravatarAvatars_Title": "Gravatar",
"SettingsEnableGravatarAvatars_Description": "Gravatar (falls verfügbar) als Absenderbild verwenden",
"SettingsEnableFavicons_Title": "Domain-Icons (Favicons)",
"SettingsEnableFavicons_Description": "Domain-Favicons (falls verfügbar) als Absenderbild verwenden",
"SettingsMailList_ClearAvatarsCache_Button": "Lösche Avatare im Cache",
"SettingsSignature_AddCustomSignature_Button": "Signatur hinzufügen", "SettingsSignature_AddCustomSignature_Button": "Signatur hinzufügen",
"SettingsSignature_AddCustomSignature_Title": "Eigene Signatur hinzufügen", "SettingsSignature_AddCustomSignature_Title": "Eigene Signatur hinzufügen",
"SettingsSignature_DeleteSignature_Title": "Signatur löschen", "SettingsSignature_DeleteSignature_Title": "Signatur löschen",
@@ -631,6 +651,8 @@
"SettingsThreads_Title": "Unterhaltungsthreading", "SettingsThreads_Title": "Unterhaltungsthreading",
"SettingsUnlinkAccounts_Description": "Entfernen Sie den Link zwischen den Konten. Dies wird Ihre Konten nicht löschen.", "SettingsUnlinkAccounts_Description": "Entfernen Sie den Link zwischen den Konten. Dies wird Ihre Konten nicht löschen.",
"SettingsUnlinkAccounts_Title": "Konten trennen", "SettingsUnlinkAccounts_Title": "Konten trennen",
"SettingsMailRendering_ActionLabels_Title": "Aktions-Labels",
"SettingsMailRendering_ActionLabels_Description": "Zeige Aktions-Labels.",
"SignatureDeleteDialog_Message": "Wollen Sie Signatur \"{0}\" wirklich löschen?", "SignatureDeleteDialog_Message": "Wollen Sie Signatur \"{0}\" wirklich löschen?",
"SignatureDeleteDialog_Title": "Signatur löschen", "SignatureDeleteDialog_Title": "Signatur löschen",
"SignatureEditorDialog_SignatureName_Placeholder": "Fügen Sie Ihre Signatur ein", "SignatureEditorDialog_SignatureName_Placeholder": "Fügen Sie Ihre Signatur ein",
@@ -676,7 +698,9 @@
"WinoUpgradeDescription": "Wino bietet 3 Accounts zum kostenlosen Start an. Wenn Sie mehr als 3 Accounts benötigen, upgraden Sie bitte.", "WinoUpgradeDescription": "Wino bietet 3 Accounts zum kostenlosen Start an. Wenn Sie mehr als 3 Accounts benötigen, upgraden Sie bitte.",
"WinoUpgradeMessage": "Auf unbegrenzte Konten upgraden", "WinoUpgradeMessage": "Auf unbegrenzte Konten upgraden",
"WinoUpgradeRemainingAccountsMessage": "{0} von {1} kostenlosen Konten verwendet.", "WinoUpgradeRemainingAccountsMessage": "{0} von {1} kostenlosen Konten verwendet.",
"Yesterday": "Gestern" "Yesterday": "Gestern",
"SettingsAppPreferences_EmailSyncInterval_Title": "Intervall für E-Mail-Synchronisierung",
"SettingsAppPreferences_EmailSyncInterval_Description": "Intervall für die automatisches E-Mail-Synchronisierung (Minuten). Diese Einstellung wird erst nach einem Neustart von Wino Mail angewendet."
} }

View File

@@ -4,9 +4,9 @@
"AccountAlias_Column_Verified": "Επαληθεύτηκε", "AccountAlias_Column_Verified": "Επαληθεύτηκε",
"AccountAlias_Disclaimer_FirstLine": "Το Wino μπορεί να εισάγει ψευδώνυμα μόνο για τους λογαριασμούς σας στο Gmail.", "AccountAlias_Disclaimer_FirstLine": "Το Wino μπορεί να εισάγει ψευδώνυμα μόνο για τους λογαριασμούς σας στο Gmail.",
"AccountAlias_Disclaimer_SecondLine": "Αν θέλετε να χρησιμοποιήσετε τα ψευδώνυμα για το Outlook ή IMAP λογαριασμό σας, παρακαλούμε να τα προσθέσετε χειροκίνητα.", "AccountAlias_Disclaimer_SecondLine": "Αν θέλετε να χρησιμοποιήσετε τα ψευδώνυμα για το Outlook ή IMAP λογαριασμό σας, παρακαλούμε να τα προσθέσετε χειροκίνητα.",
"AccountCacheReset_Title": "Account Cache Reset", "AccountCacheReset_Title": "Επαναφορά Κρυφής Μνήμης Λογαριασμού",
"AccountCacheReset_Message": "This account requires full re-sychronization to continue working. Please wait while Wino re-synchronizes your messages...", "AccountCacheReset_Message": "Αυτός ο λογαριασμός απαιτεί πλήρη επανασυγχρονισμό για να συνεχίσει να δουλεύει. Παρακαλώ περιμένετε ενώ ο Wino επανασυγχρονίζει τα μηνύματά σας...",
"AccountContactNameYou": "You", "AccountContactNameYou": "Εσείς",
"AccountCreationDialog_Completed": "όλα έτοιμα", "AccountCreationDialog_Completed": "όλα έτοιμα",
"AccountCreationDialog_FetchingEvents": "Ανάκτηση συμβάντων ημερολογίου.", "AccountCreationDialog_FetchingEvents": "Ανάκτηση συμβάντων ημερολογίου.",
"AccountCreationDialog_FetchingProfileInformation": "Λήψη λεπτομερειών προφίλ.", "AccountCreationDialog_FetchingProfileInformation": "Λήψη λεπτομερειών προφίλ.",
@@ -22,6 +22,10 @@
"AccountPickerDialog_Title": "Επιλέξτε έναν λογαριασμό", "AccountPickerDialog_Title": "Επιλέξτε έναν λογαριασμό",
"AccountSettingsDialog_AccountName": "Εμφανιζόμενο Όνομα Αποστολέα", "AccountSettingsDialog_AccountName": "Εμφανιζόμενο Όνομα Αποστολέα",
"AccountSettingsDialog_AccountNamePlaceholder": "πχ. Γιώργος Παπαδάκης", "AccountSettingsDialog_AccountNamePlaceholder": "πχ. Γιώργος Παπαδάκης",
"AccountDetailsPage_Title": "Πληροφορίες λογαριασμού",
"AccountDetailsPage_Description": "Αλλάξτε το όνομα του λογαριασμού στο Wino και ορίστε το επιθυμητό όνομα αποστολέα.",
"AccountDetailsPage_ColorPicker_Title": "Χρώμα λογαριασμού",
"AccountDetailsPage_ColorPicker_Description": "Αναθέστε ένα νέο χρώμα λογαριασμού για να χρωματίσετε το σύμβολο του στη λίστα.",
"AddHyperlink": "Προσθήκη", "AddHyperlink": "Προσθήκη",
"AppCloseBackgroundSynchronizationWarningTitle": "Συγχρονισμός Παρασκηνίου", "AppCloseBackgroundSynchronizationWarningTitle": "Συγχρονισμός Παρασκηνίου",
"AppCloseStartupLaunchDisabledWarningMessageFirstLine": "Η εφαρμογή δεν έχει οριστεί για εκκίνηση κατά την έναρξη των Windows.", "AppCloseStartupLaunchDisabledWarningMessageFirstLine": "Η εφαρμογή δεν έχει οριστεί για εκκίνηση κατά την έναρξη των Windows.",
@@ -184,7 +188,7 @@
"Exception_ImapClientPoolFailed": "Αποτυχία συγκέντρωσης πελάτη IMAP.", "Exception_ImapClientPoolFailed": "Αποτυχία συγκέντρωσης πελάτη IMAP.",
"Exception_InboxNotAvailable": "Δεν ήταν δυνατή η ρύθμιση φακέλων λογαριασμού.", "Exception_InboxNotAvailable": "Δεν ήταν δυνατή η ρύθμιση φακέλων λογαριασμού.",
"Exception_InvalidSystemFolderConfiguration": "Η διαμόρφωση του φακέλου συστήματος δεν είναι έγκυρη. Ελέγξτε τη διαμόρφωση και προσπαθήστε ξανά.", "Exception_InvalidSystemFolderConfiguration": "Η διαμόρφωση του φακέλου συστήματος δεν είναι έγκυρη. Ελέγξτε τη διαμόρφωση και προσπαθήστε ξανά.",
"Exception_InvalidMultiAccountMoveTarget": "You can't move multiple items that belong to different accounts in linked account.", "Exception_InvalidMultiAccountMoveTarget": "Δεν μπορείτε να μετακινήσετε πολλά στοιχεία που ανήκουν σε διαφορετικούς λογαριασμούς σε συνδεδεμένο λογαριασμό.",
"Exception_MailProcessing": "Αυτό το μήνυμα εξακολουθεί να επεξεργάζεται. Παρακαλώ δοκιμάστε ξανά μετά από λίγα δευτερόλεπτα.", "Exception_MailProcessing": "Αυτό το μήνυμα εξακολουθεί να επεξεργάζεται. Παρακαλώ δοκιμάστε ξανά μετά από λίγα δευτερόλεπτα.",
"Exception_MissingAlias": "Το κύριο ψευδώνυμο δεν υπάρχει για αυτόν τον λογαριασμό. Η δημιουργία προχείρου απέτυχε.", "Exception_MissingAlias": "Το κύριο ψευδώνυμο δεν υπάρχει για αυτόν τον λογαριασμό. Η δημιουργία προχείρου απέτυχε.",
"Exception_NullAssignedAccount": "Ο εκχωρημένος λογαριασμός είναι κενός", "Exception_NullAssignedAccount": "Ο εκχωρημένος λογαριασμός είναι κενός",
@@ -217,9 +221,9 @@
"GeneralTitle_Error": "Σφάλμα", "GeneralTitle_Error": "Σφάλμα",
"GeneralTitle_Info": "Πληροφορίες", "GeneralTitle_Info": "Πληροφορίες",
"GeneralTitle_Warning": "Προειδοποίηση", "GeneralTitle_Warning": "Προειδοποίηση",
"GmailServiceDisabled_Title": "Gmail Error", "GmailServiceDisabled_Title": "Σφάλμα Gmail",
"GmailServiceDisabled_Message": "Your Google Workspace account seems to be disabled for Gmail service. Please contact your administrator to enable Gmail service for your account.", "GmailServiceDisabled_Message": "Ο λογαριασμός σας στο Google Workspace φαίνεται να είναι απενεργοποιημένος για την υπηρεσία Gmail. Επικοινωνήστε με το διαχειριστή σας για να ενεργοποιήσετε την υπηρεσία Gmail για το λογαριασμό σας.",
"GmailArchiveFolderNameOverride": "Archive", "GmailArchiveFolderNameOverride": "Αρχειοθέτηση",
"HoverActionOption_Archive": "Αρχειοθέτηση", "HoverActionOption_Archive": "Αρχειοθέτηση",
"HoverActionOption_Delete": "Διαγραφή", "HoverActionOption_Delete": "Διαγραφή",
"HoverActionOption_MoveJunk": "Μετακίνηση στα Ανεπιθύμητα", "HoverActionOption_MoveJunk": "Μετακίνηση στα Ανεπιθύμητα",
@@ -228,22 +232,22 @@
"ImageRenderingDisabled": "Η αποτύπωση εικόνων είναι απενεργοποιημένη για αυτό το μήνυμα.", "ImageRenderingDisabled": "Η αποτύπωση εικόνων είναι απενεργοποιημένη για αυτό το μήνυμα.",
"ImapAdvancedSetupDialog_AuthenticationMethod": "Μέθοδος επαλήθευσης", "ImapAdvancedSetupDialog_AuthenticationMethod": "Μέθοδος επαλήθευσης",
"ImapAdvancedSetupDialog_ConnectionSecurity": "Ασφάλεια σύνδεσης", "ImapAdvancedSetupDialog_ConnectionSecurity": "Ασφάλεια σύνδεσης",
"IMAPAdvancedSetupDialog_ValidationAuthMethodRequired": "Authentication method is required", "IMAPAdvancedSetupDialog_ValidationAuthMethodRequired": "Απαιτείται μέθοδος ταυτοποίησης",
"IMAPAdvancedSetupDialog_ValidationConnectionSecurityRequired": "Connection security type is required", "IMAPAdvancedSetupDialog_ValidationConnectionSecurityRequired": "Απαιτείται ο τύπος ασφάλειας σύνδεσης",
"IMAPAdvancedSetupDialog_ValidationDisplayNameRequired": "Display name is required", "IMAPAdvancedSetupDialog_ValidationDisplayNameRequired": "Απαιτείται εμφανιζόμενο όνομα",
"IMAPAdvancedSetupDialog_ValidationEmailInvalid": "Please enter a valid email address", "IMAPAdvancedSetupDialog_ValidationEmailInvalid": "Παρακαλώ εισάγετε μια έγκυρη διεύθυνση email",
"IMAPAdvancedSetupDialog_ValidationEmailRequired": "Email address is required", "IMAPAdvancedSetupDialog_ValidationEmailRequired": "Απαιτείται η διεύθυνση email",
"IMAPAdvancedSetupDialog_ValidationErrorTitle": "Please check the following:", "IMAPAdvancedSetupDialog_ValidationErrorTitle": "Παρακαλούμε ελέγξτε τα εξής:",
"IMAPAdvancedSetupDialog_ValidationIncomingPortInvalid": "Incoming port must be between 1-65535", "IMAPAdvancedSetupDialog_ValidationIncomingPortInvalid": "Η εισερχόμενη θύρα πρέπει να είναι μεταξύ 1-65535",
"IMAPAdvancedSetupDialog_ValidationIncomingPortRequired": "Incoming server port is required", "IMAPAdvancedSetupDialog_ValidationIncomingPortRequired": "Η εισερχόμενη θύρα διακομιστή απαιτείται",
"IMAPAdvancedSetupDialog_ValidationIncomingServerRequired": "Incoming server address is required", "IMAPAdvancedSetupDialog_ValidationIncomingServerRequired": "Απαιτείται διεύθυνση διακομιστή εισερχομένων",
"IMAPAdvancedSetupDialog_ValidationOutgoingPasswordRequired": "Outgoing server password is required", "IMAPAdvancedSetupDialog_ValidationOutgoingPasswordRequired": "Απαιτείται κωδικός πρόσβασης διακομιστή εξερχομένων",
"IMAPAdvancedSetupDialog_ValidationOutgoingPortInvalid": "Outgoing port must be between 1-65535", "IMAPAdvancedSetupDialog_ValidationOutgoingPortInvalid": "Η εξερχόμενη θύρα πρέπει να είναι μεταξύ 1-65535",
"IMAPAdvancedSetupDialog_ValidationOutgoingPortRequired": "Outgoing server port is required", "IMAPAdvancedSetupDialog_ValidationOutgoingPortRequired": "Απαιτείται θύρα διακομιστή εξερχομένων",
"IMAPAdvancedSetupDialog_ValidationOutgoingServerRequired": "Outgoing server address is required", "IMAPAdvancedSetupDialog_ValidationOutgoingServerRequired": "Απαιτείται διεύθυνση διακομιστή εξερχομένων",
"IMAPAdvancedSetupDialog_ValidationOutgoingUsernameRequired": "Outgoing server username is required", "IMAPAdvancedSetupDialog_ValidationOutgoingUsernameRequired": "Απαιτείται όνομα χρήστη εξερχόμενου διακομιστή",
"IMAPAdvancedSetupDialog_ValidationPasswordRequired": "Password is required", "IMAPAdvancedSetupDialog_ValidationPasswordRequired": "Απαιτείται κωδικός πρόσβασης",
"IMAPAdvancedSetupDialog_ValidationUsernameRequired": "Username is required", "IMAPAdvancedSetupDialog_ValidationUsernameRequired": "Απαιτείται όνομα χρήστη",
"ImapAuthenticationMethod_Auto": "Αυτόματο", "ImapAuthenticationMethod_Auto": "Αυτόματο",
"ImapAuthenticationMethod_CramMD5": "CRAM-MD5", "ImapAuthenticationMethod_CramMD5": "CRAM-MD5",
"ImapAuthenticationMethod_DigestMD5": "DIGEST-MD5", "ImapAuthenticationMethod_DigestMD5": "DIGEST-MD5",
@@ -256,6 +260,11 @@
"ImapConnectionSecurity_SslTls": "SSL/TLS", "ImapConnectionSecurity_SslTls": "SSL/TLS",
"ImapConnectionSecurity_StartTls": "STARTTLS", "ImapConnectionSecurity_StartTls": "STARTTLS",
"IMAPSetupDialog_AccountType": "Τύπος λογαριασμού", "IMAPSetupDialog_AccountType": "Τύπος λογαριασμού",
"IMAPSetupDialog_ValidationSuccess_Title": "Επιτυχία",
"IMAPSetupDialog_ValidationSuccess_Message": "Επιτυχής επικύρωση",
"IMAPSetupDialog_SaveImapSuccess_Title": "Success",
"IMAPSetupDialog_SaveImapSuccess_Message": "IMAP settings saved successfuly.",
"IMAPSetupDialog_ValidationFailed_Title": "Αποτυχία επικύρωσης διακομιστή IMAP.",
"IMAPSetupDialog_CertificateAllowanceRequired_Row0": "Αυτός ο διακομιστής ζητά μια χειραψία SSL για να συνεχίσει. Παρακαλώ επιβεβαιώστε τις λεπτομέρειες του πιστοποιητικού παρακάτω.", "IMAPSetupDialog_CertificateAllowanceRequired_Row0": "Αυτός ο διακομιστής ζητά μια χειραψία SSL για να συνεχίσει. Παρακαλώ επιβεβαιώστε τις λεπτομέρειες του πιστοποιητικού παρακάτω.",
"IMAPSetupDialog_CertificateAllowanceRequired_Row1": "Επιτρέψτε στην χειραψία να συνεχίσει τη ρύθμιση του λογαριασμού σας.", "IMAPSetupDialog_CertificateAllowanceRequired_Row1": "Επιτρέψτε στην χειραψία να συνεχίσει τη ρύθμιση του λογαριασμού σας.",
"IMAPSetupDialog_CertificateDenied": "Ο χρήστης δεν εξουσιοδότησε την χειραψία με το πιστοποιητικό.", "IMAPSetupDialog_CertificateDenied": "Ο χρήστης δεν εξουσιοδότησε την χειραψία με το πιστοποιητικό.",
@@ -270,6 +279,8 @@
"IMAPSetupDialog_DisplayNamePlaceholder": "πχ. Γιώργος Παπαδάκης", "IMAPSetupDialog_DisplayNamePlaceholder": "πχ. Γιώργος Παπαδάκης",
"IMAPSetupDialog_IncomingMailServer": "Διακομιστής εισερχόμενων mail", "IMAPSetupDialog_IncomingMailServer": "Διακομιστής εισερχόμενων mail",
"IMAPSetupDialog_IncomingMailServerPort": "Πύλη", "IMAPSetupDialog_IncomingMailServerPort": "Πύλη",
"IMAPSetupDialog_IMAPSettings": "Ρυθμίσεις Διακομιστή IMAP",
"IMAPSetupDialog_SMTPSettings": "Ρυθμίσεις Διακομιστή SMTP",
"IMAPSetupDialog_MailAddress": "Διεύθυνση ηλεκτρονικού ταχυδρομείου", "IMAPSetupDialog_MailAddress": "Διεύθυνση ηλεκτρονικού ταχυδρομείου",
"IMAPSetupDialog_MailAddressPlaceholder": "someone@example.com", "IMAPSetupDialog_MailAddressPlaceholder": "someone@example.com",
"IMAPSetupDialog_OutgoingMailServer": "Εξερχόμενος διακομιστής αλληλογραφίας (SMTP)", "IMAPSetupDialog_OutgoingMailServer": "Εξερχόμενος διακομιστής αλληλογραφίας (SMTP)",
@@ -423,9 +434,9 @@
"Notifications_MultipleNotificationsTitle": "Νέα Αλληλογραφία", "Notifications_MultipleNotificationsTitle": "Νέα Αλληλογραφία",
"Notifications_WinoUpdatedMessage": "Ρίξτε μια ματιά στη νέα έκδοση {0}", "Notifications_WinoUpdatedMessage": "Ρίξτε μια ματιά στη νέα έκδοση {0}",
"Notifications_WinoUpdatedTitle": "Το Wino Mail έχει ενημερωθεί.", "Notifications_WinoUpdatedTitle": "Το Wino Mail έχει ενημερωθεί.",
"OnlineSearchFailed_Message": "Failed to perform search\n{0}\n\nListing offline mails.", "OnlineSearchFailed_Message": "Αποτυχία εκτέλεσης αναζήτησης\n{0}\n\nΕμφάνιση μηνυμάτων εκτός σύνδεσης.",
"OnlineSearchTry_Line1": "Can't find what you are looking for?", "OnlineSearchTry_Line1": "Δεν μπορείτε να βρείτε αυτό που ψάχνετε;",
"OnlineSearchTry_Line2": "Try online search.", "OnlineSearchTry_Line2": "Δοκιμάστε την online αναζήτηση.",
"Other": "Άλλα", "Other": "Άλλα",
"PaneLengthOption_Default": "Προεπιλογή", "PaneLengthOption_Default": "Προεπιλογή",
"PaneLengthOption_ExtraLarge": "Πολύ Μεγάλο", "PaneLengthOption_ExtraLarge": "Πολύ Μεγάλο",
@@ -443,11 +454,11 @@
"ProviderDetail_IMAP_Title": "Διακομιστής IMAP", "ProviderDetail_IMAP_Title": "Διακομιστής IMAP",
"ProviderDetail_Yahoo_Description": "Λογαριασμός Yahoo", "ProviderDetail_Yahoo_Description": "Λογαριασμός Yahoo",
"ProviderDetail_Yahoo_Title": "Ταχυδρομείο Yahoo", "ProviderDetail_Yahoo_Title": "Ταχυδρομείο Yahoo",
"QuickEventDialog_EventName": "Event name", "QuickEventDialog_EventName": "Όνομα γεγονότος",
"QuickEventDialog_IsAllDay": "All day", "QuickEventDialog_IsAllDay": "Όλη μέρα",
"QuickEventDialog_Location": "Location", "QuickEventDialog_Location": "Τοποθεσία",
"QuickEventDialog_RemindMe": "Remind me", "QuickEventDialog_RemindMe": "Θύμισέ μου",
"QuickEventDialogMoreDetailsButtonText": "More details", "QuickEventDialogMoreDetailsButtonText": "Κι άλλες λεπτομέρειες",
"Reader_SaveAllAttachmentButtonText": "Αποθήκευση όλων των συνημμένων", "Reader_SaveAllAttachmentButtonText": "Αποθήκευση όλων των συνημμένων",
"Results": "Αποτελέσματα", "Results": "Αποτελέσματα",
"Right": "Δεξιά", "Right": "Δεξιά",
@@ -455,6 +466,8 @@
"SearchingIn": "Αναζήτηση σε", "SearchingIn": "Αναζήτηση σε",
"SearchPivotName": "Αποτελέσματα", "SearchPivotName": "Αποτελέσματα",
"SettingConfigureSpecialFolders_Button": "Διαμόρφωση", "SettingConfigureSpecialFolders_Button": "Διαμόρφωση",
"SettingsEditAccountDetails_IMAPConfiguration_Title": "Διαμόρφωση IMAP/SMTP",
"SettingsEditAccountDetails_IMAPConfiguration_Description": "Αλλάξτε τις ρυθμίσεις του διακομιστή εισερχομένων/εξερχομένων σας.",
"SettingsAbout_Description": "Μάθετε περισσότερα για το Wino.", "SettingsAbout_Description": "Μάθετε περισσότερα για το Wino.",
"SettingsAbout_Title": "Σχετικά", "SettingsAbout_Title": "Σχετικά",
"SettingsAboutGithub_Description": "Μεταβείτε στο αποθετήριο GitHub για τον ανιχνευτή προβλημάτων.", "SettingsAboutGithub_Description": "Μεταβείτε στο αποθετήριο GitHub για τον ανιχνευτή προβλημάτων.",
@@ -473,10 +486,10 @@
"SettingsAppPreferences_CloseBehavior_Description": "Τί πρέπει να συμβεί όταν κλείσετε την εφαρμογή;", "SettingsAppPreferences_CloseBehavior_Description": "Τί πρέπει να συμβεί όταν κλείσετε την εφαρμογή;",
"SettingsAppPreferences_CloseBehavior_Title": "Συμπεριφορά κλεισίματος εφαρμογής", "SettingsAppPreferences_CloseBehavior_Title": "Συμπεριφορά κλεισίματος εφαρμογής",
"SettingsAppPreferences_Description": "Γενικές ρυθμίσεις / προτιμήσεις για το Wino Mail.", "SettingsAppPreferences_Description": "Γενικές ρυθμίσεις / προτιμήσεις για το Wino Mail.",
"SettingsAppPreferences_SearchMode_Description": "Set whether Wino should check fetched mails first while doing a search or ask your mail server online. Local search is always faster and you can always do an online search if your mail is not in the results.", "SettingsAppPreferences_SearchMode_Description": "Ορίστε αν ο Wino θα πρέπει να ελέγχει πρώτα τα ληφθέντα μηνύματα κατά τη διάρκεια αναζήτησης ή ρωτήστε το διακομιστή αλληλογραφίας σας online. Η τοπική αναζήτηση είναι πάντα πιο γρήγορη και μπορείτε πάντα να κάνετε μια online αναζήτηση αν το ταχυδρομείο σας δεν είναι στα αποτελέσματα.",
"SettingsAppPreferences_SearchMode_Local": "Local", "SettingsAppPreferences_SearchMode_Local": "Τοπικό",
"SettingsAppPreferences_SearchMode_Online": "Online", "SettingsAppPreferences_SearchMode_Online": "Online",
"SettingsAppPreferences_SearchMode_Title": "Default search mode", "SettingsAppPreferences_SearchMode_Title": "Προεπιλεγμένη λειτουργία αναζήτησης",
"SettingsAppPreferences_ServerBackgroundingMode_Invisible_Description": "Το Wino Mail θα συνεχίσει να εκτελείται στο παρασκήνιο. Θα ειδοποιηθείτε καθώς φτάνουν νέα μηνύματα.", "SettingsAppPreferences_ServerBackgroundingMode_Invisible_Description": "Το Wino Mail θα συνεχίσει να εκτελείται στο παρασκήνιο. Θα ειδοποιηθείτε καθώς φτάνουν νέα μηνύματα.",
"SettingsAppPreferences_ServerBackgroundingMode_Invisible_Title": "Εκτέλεση στο παρασκήνιο", "SettingsAppPreferences_ServerBackgroundingMode_Invisible_Title": "Εκτέλεση στο παρασκήνιο",
"SettingsAppPreferences_ServerBackgroundingMode_MinimizeTray_Description": "Το Wino Mail θα συνεχίσει να εκτελείται στο συαρτάρι συστήματος. Διαθέσιμο για εκκίνηση κάνοντας κλικ σε ένα εικονίδιο. Θα ειδοποιηθείτε καθώς φτάνουν νέα μηνύματα.", "SettingsAppPreferences_ServerBackgroundingMode_MinimizeTray_Description": "Το Wino Mail θα συνεχίσει να εκτελείται στο συαρτάρι συστήματος. Διαθέσιμο για εκκίνηση κάνοντας κλικ σε ένα εικονίδιο. Θα ειδοποιηθείτε καθώς φτάνουν νέα μηνύματα.",
@@ -508,11 +521,11 @@
"SettingsCustomTheme_Title": "Προσαρμοσμένο Θέμα", "SettingsCustomTheme_Title": "Προσαρμοσμένο Θέμα",
"SettingsDeleteAccount_Description": "Διαγραφή όλων των e-mails και διαπιστευτηρίων που σχετίζονται με αυτόν τον λογαριασμό.", "SettingsDeleteAccount_Description": "Διαγραφή όλων των e-mails και διαπιστευτηρίων που σχετίζονται με αυτόν τον λογαριασμό.",
"SettingsDeleteAccount_Title": "Διαγραφή αυτού του λογαριασμού", "SettingsDeleteAccount_Title": "Διαγραφή αυτού του λογαριασμού",
"SettingsDeleteProtection_Description": "Πρέπει να Wino ζητήσει την επιβεβαίωση κάθε φορά που προσπαθείτε να διαγράψετε μόνιμα ένα μήνυμα χρησιμοποιώντας το Shift + Del;", "SettingsDeleteProtection_Description": "Should Wino ask you for confirmation every time you try to permanently delete a mail using Shift + Del keys?",
"SettingsDeleteProtection_Title": "Προστασία Μόνιμης Διαγραφής", "SettingsDeleteProtection_Title": "Προστασία Μόνιμης Διαγραφής",
"SettingsDiagnostics_Description": "Για προγραμματιστές", "SettingsDiagnostics_Description": "Για προγραμματιστές",
"SettingsDiagnostics_DiagnosticId_Description": "Share this ID with the developers when asked to get help for the issues you experience in Wino Mail.", "SettingsDiagnostics_DiagnosticId_Description": "Μοιραστείτε αυτό το ID με τους προγραμματιστές όταν σας ζητηθεί να λάβετε βοήθεια για τα θέματα που αντιμετωπίζετε στο Wino Mail.",
"SettingsDiagnostics_DiagnosticId_Title": "Diagnostic ID", "SettingsDiagnostics_DiagnosticId_Title": "Διαγνωστικό ID",
"SettingsDiagnostics_Title": "Διαγνωστικά", "SettingsDiagnostics_Title": "Διαγνωστικά",
"SettingsDiscord_Description": "Λήψη τακτικών ενημερώσεων για την ανάπτυξη, συμμετοχή σε συζητήσεις προόδου και παροχή σχολίων.", "SettingsDiscord_Description": "Λήψη τακτικών ενημερώσεων για την ανάπτυξη, συμμετοχή σε συζητήσεις προόδου και παροχή σχολίων.",
"SettingsDiscord_Title": "Κανάλι Discord", "SettingsDiscord_Title": "Κανάλι Discord",
@@ -556,7 +569,7 @@
"SettingsLinkedAccountsSave_Description": "Τροποποίηση του τρέχοντος συνδέσμου με τους νέους λογαριασμούς.", "SettingsLinkedAccountsSave_Description": "Τροποποίηση του τρέχοντος συνδέσμου με τους νέους λογαριασμούς.",
"SettingsLinkedAccountsSave_Title": "Αποθήκευση Αλλαγών", "SettingsLinkedAccountsSave_Title": "Αποθήκευση Αλλαγών",
"SettingsLoadImages_Title": "Αυτόματη φόρτωση εικόνων", "SettingsLoadImages_Title": "Αυτόματη φόρτωση εικόνων",
"SettingsLoadPlaintextLinks_Title": "Convert plaintext links to clickable links", "SettingsLoadPlaintextLinks_Title": "Μετατροπή συνδέσμων απλού κειμένου σε συνδέσμους με δυνατότητα κλικ",
"SettingsLoadStyles_Title": "Αυτόματη φόρτωση στυλ", "SettingsLoadStyles_Title": "Αυτόματη φόρτωση στυλ",
"SettingsMailListActionBar_Description": "Απόκρυψη/εμφάνιση γραμμής ενεργειών στην κορυφή της λίστας μηνυμάτων.", "SettingsMailListActionBar_Description": "Απόκρυψη/εμφάνιση γραμμής ενεργειών στην κορυφή της λίστας μηνυμάτων.",
"SettingsMailListActionBar_Title": "Εμφάνιση ενεργειών λίστας αλληλογραφίας", "SettingsMailListActionBar_Title": "Εμφάνιση ενεργειών λίστας αλληλογραφίας",
@@ -566,6 +579,8 @@
"SettingsManageAccountSettings_Title": "Ρυθμίσεις Διαχείρισης Λογαριασμού", "SettingsManageAccountSettings_Title": "Ρυθμίσεις Διαχείρισης Λογαριασμού",
"SettingsManageAliases_Description": "Δείτε τα ψευδώνυμα ηλεκτρονικού ταχυδρομείου που έχουν εκχωρηθεί για αυτόν το λογαριασμό, ενημερώστε ή διαγράψτε τα.", "SettingsManageAliases_Description": "Δείτε τα ψευδώνυμα ηλεκτρονικού ταχυδρομείου που έχουν εκχωρηθεί για αυτόν το λογαριασμό, ενημερώστε ή διαγράψτε τα.",
"SettingsManageAliases_Title": "Ψευδώνυμα", "SettingsManageAliases_Title": "Ψευδώνυμα",
"SettingsEditAccountDetails_Title": "Επεξεργασία Στοιχείων Λογαριασμού",
"SettingsEditAccountDetails_Description": "Αλλάξτε το όνομα λογαριασμού, το όνομα του αποστολέα και ορίστε ένα νέο χρώμα αν θέλετε.",
"SettingsManageLink_Description": "Μετακίνηση αντικειμένων για προσθήκη νέου συνδέσμου ή κατάργηση υπάρχοντος συνδέσμου.", "SettingsManageLink_Description": "Μετακίνηση αντικειμένων για προσθήκη νέου συνδέσμου ή κατάργηση υπάρχοντος συνδέσμου.",
"SettingsManageLink_Title": "Διαχείριση Συνδέσμου", "SettingsManageLink_Title": "Διαχείριση Συνδέσμου",
"SettingsMarkAsRead_Description": "Αλλάξτε τι πρέπει να συμβεί στο επιλεγμένο αντικείμενο.", "SettingsMarkAsRead_Description": "Αλλάξτε τι πρέπει να συμβεί στο επιλεγμένο αντικείμενο.",
@@ -610,6 +625,11 @@
"SettingsShowPreviewText_Title": "Εμφάνιση Κειμένου Προεπισκόπησης", "SettingsShowPreviewText_Title": "Εμφάνιση Κειμένου Προεπισκόπησης",
"SettingsShowSenderPictures_Description": "Απόκρυψη/εμφάνιση της μικρογραφίας του αποστολέα.", "SettingsShowSenderPictures_Description": "Απόκρυψη/εμφάνιση της μικρογραφίας του αποστολέα.",
"SettingsShowSenderPictures_Title": "Εμφάνιση Avatars Αποστολέα", "SettingsShowSenderPictures_Title": "Εμφάνιση Avatars Αποστολέα",
"SettingsEnableGravatarAvatars_Title": "Gravatar",
"SettingsEnableGravatarAvatars_Description": "Use gravatar (if available) as sender picture",
"SettingsEnableFavicons_Title": "Domain icons (Favicons)",
"SettingsEnableFavicons_Description": "Use domain favicons (if available) as sender picture",
"SettingsMailList_ClearAvatarsCache_Button": "Clear cached avatars",
"SettingsSignature_AddCustomSignature_Button": "Προσθήκη υπογραφής", "SettingsSignature_AddCustomSignature_Button": "Προσθήκη υπογραφής",
"SettingsSignature_AddCustomSignature_Title": "Προσθήκη προσαρμοσμένης υπογραφής", "SettingsSignature_AddCustomSignature_Title": "Προσθήκη προσαρμοσμένης υπογραφής",
"SettingsSignature_DeleteSignature_Title": "Διαγραφή υπογραφής", "SettingsSignature_DeleteSignature_Title": "Διαγραφή υπογραφής",
@@ -631,6 +651,8 @@
"SettingsThreads_Title": "Νηματοποίηση Συζήτησης", "SettingsThreads_Title": "Νηματοποίηση Συζήτησης",
"SettingsUnlinkAccounts_Description": "Αφαιρέστε τη σύνδεση μεταξύ των λογαριασμών. Δε θα διαγράψει τους λογαριασμούς σας.", "SettingsUnlinkAccounts_Description": "Αφαιρέστε τη σύνδεση μεταξύ των λογαριασμών. Δε θα διαγράψει τους λογαριασμούς σας.",
"SettingsUnlinkAccounts_Title": "Αποδέσμευση Λογαριασμών", "SettingsUnlinkAccounts_Title": "Αποδέσμευση Λογαριασμών",
"SettingsMailRendering_ActionLabels_Title": "Action labels",
"SettingsMailRendering_ActionLabels_Description": "Show action labels.",
"SignatureDeleteDialog_Message": "Σίγουρα θέλετε να διαγράψετε την υπογραφή \"{0}\";", "SignatureDeleteDialog_Message": "Σίγουρα θέλετε να διαγράψετε την υπογραφή \"{0}\";",
"SignatureDeleteDialog_Title": "Διαγραφή υπογραφής", "SignatureDeleteDialog_Title": "Διαγραφή υπογραφής",
"SignatureEditorDialog_SignatureName_Placeholder": "Ονομάστε την υπογραφή σας", "SignatureEditorDialog_SignatureName_Placeholder": "Ονομάστε την υπογραφή σας",
@@ -676,7 +698,9 @@
"WinoUpgradeDescription": "Το Wino προσφέρει 3 λογαριασμούς για να ξεκινήσετε δωρεάν. Εάν χρειάζεστε περισσότερους από 3, παρακαλώ αναβαθμίστε", "WinoUpgradeDescription": "Το Wino προσφέρει 3 λογαριασμούς για να ξεκινήσετε δωρεάν. Εάν χρειάζεστε περισσότερους από 3, παρακαλώ αναβαθμίστε",
"WinoUpgradeMessage": "Αναβάθμιση σε Απεριόριστους Λογαριασμούς", "WinoUpgradeMessage": "Αναβάθμιση σε Απεριόριστους Λογαριασμούς",
"WinoUpgradeRemainingAccountsMessage": "Χρησιμοποιούνται {0} από τους {1} δωρεάν λογαριασμούς.", "WinoUpgradeRemainingAccountsMessage": "Χρησιμοποιούνται {0} από τους {1} δωρεάν λογαριασμούς.",
"Yesterday": "Χθες" "Yesterday": "Χθες",
"SettingsAppPreferences_EmailSyncInterval_Title": "Email sync interval",
"SettingsAppPreferences_EmailSyncInterval_Description": "Automatic email synchronization interval (minutes). This setting will be applied only after restarting Wino Mail."
} }

View File

@@ -22,6 +22,10 @@
"AccountPickerDialog_Title": "Pick an account", "AccountPickerDialog_Title": "Pick an account",
"AccountSettingsDialog_AccountName": "Sender Display Name", "AccountSettingsDialog_AccountName": "Sender Display Name",
"AccountSettingsDialog_AccountNamePlaceholder": "eg. John Doe", "AccountSettingsDialog_AccountNamePlaceholder": "eg. John Doe",
"AccountDetailsPage_Title": "Account info",
"AccountDetailsPage_Description": "Change the name of the account in Wino and set desired sender name.",
"AccountDetailsPage_ColorPicker_Title": "Account color",
"AccountDetailsPage_ColorPicker_Description": "Assign a new account color to colorize its symbol in the list.",
"AddHyperlink": "Add", "AddHyperlink": "Add",
"AppCloseBackgroundSynchronizationWarningTitle": "Background Synchronization", "AppCloseBackgroundSynchronizationWarningTitle": "Background Synchronization",
"AppCloseStartupLaunchDisabledWarningMessageFirstLine": "Application has not been set to launch on Windows startup.", "AppCloseStartupLaunchDisabledWarningMessageFirstLine": "Application has not been set to launch on Windows startup.",
@@ -256,6 +260,11 @@
"ImapConnectionSecurity_SslTls": "SSL/TLS", "ImapConnectionSecurity_SslTls": "SSL/TLS",
"ImapConnectionSecurity_StartTls": "STARTTLS", "ImapConnectionSecurity_StartTls": "STARTTLS",
"IMAPSetupDialog_AccountType": "Account type", "IMAPSetupDialog_AccountType": "Account type",
"IMAPSetupDialog_ValidationSuccess_Title": "Success",
"IMAPSetupDialog_ValidationSuccess_Message": "Validation successful",
"IMAPSetupDialog_SaveImapSuccess_Title": "Success",
"IMAPSetupDialog_SaveImapSuccess_Message": "IMAP settings saved successfuly.",
"IMAPSetupDialog_ValidationFailed_Title": "IMAP Server validation failed.",
"IMAPSetupDialog_CertificateAllowanceRequired_Row0": "This server is requesting a SSL handshake to continue. Please confirm the certificate details below.", "IMAPSetupDialog_CertificateAllowanceRequired_Row0": "This server is requesting a SSL handshake to continue. Please confirm the certificate details below.",
"IMAPSetupDialog_CertificateAllowanceRequired_Row1": "Allow the handshake to continue setting up your account.", "IMAPSetupDialog_CertificateAllowanceRequired_Row1": "Allow the handshake to continue setting up your account.",
"IMAPSetupDialog_CertificateDenied": "User didn't authorize the handshake with the certificate.", "IMAPSetupDialog_CertificateDenied": "User didn't authorize the handshake with the certificate.",
@@ -270,6 +279,8 @@
"IMAPSetupDialog_DisplayNamePlaceholder": "eg. John Doe", "IMAPSetupDialog_DisplayNamePlaceholder": "eg. John Doe",
"IMAPSetupDialog_IncomingMailServer": "Incoming mail server", "IMAPSetupDialog_IncomingMailServer": "Incoming mail server",
"IMAPSetupDialog_IncomingMailServerPort": "Port", "IMAPSetupDialog_IncomingMailServerPort": "Port",
"IMAPSetupDialog_IMAPSettings": "IMAP Server Settings",
"IMAPSetupDialog_SMTPSettings": "SMTP Server Settings",
"IMAPSetupDialog_MailAddress": "Email address", "IMAPSetupDialog_MailAddress": "Email address",
"IMAPSetupDialog_MailAddressPlaceholder": "someone@example.com", "IMAPSetupDialog_MailAddressPlaceholder": "someone@example.com",
"IMAPSetupDialog_OutgoingMailServer": "Outgoing (SMTP) mail server", "IMAPSetupDialog_OutgoingMailServer": "Outgoing (SMTP) mail server",
@@ -455,6 +466,8 @@
"SearchingIn": "Searching in", "SearchingIn": "Searching in",
"SearchPivotName": "Results", "SearchPivotName": "Results",
"SettingConfigureSpecialFolders_Button": "Configure", "SettingConfigureSpecialFolders_Button": "Configure",
"SettingsEditAccountDetails_IMAPConfiguration_Title": "IMAP/SMTP Configuration",
"SettingsEditAccountDetails_IMAPConfiguration_Description": "Change your incoming/outgoing server settings.",
"SettingsAbout_Description": "Learn more about Wino.", "SettingsAbout_Description": "Learn more about Wino.",
"SettingsAbout_Title": "About", "SettingsAbout_Title": "About",
"SettingsAboutGithub_Description": "Go to issue tracker GitHub repository.", "SettingsAboutGithub_Description": "Go to issue tracker GitHub repository.",
@@ -508,7 +521,7 @@
"SettingsCustomTheme_Title": "Custom Theme", "SettingsCustomTheme_Title": "Custom Theme",
"SettingsDeleteAccount_Description": "Delete all e-mails and credentials associated with this account.", "SettingsDeleteAccount_Description": "Delete all e-mails and credentials associated with this account.",
"SettingsDeleteAccount_Title": "Delete this account", "SettingsDeleteAccount_Title": "Delete this account",
"SettingsDeleteProtection_Description": "Should Wino ask you for comfirmation every time you try to permanently delete a mail using Shift + Del keys?", "SettingsDeleteProtection_Description": "Should Wino ask you for confirmation every time you try to permanently delete a mail using Shift + Del keys?",
"SettingsDeleteProtection_Title": "Permanent Delete Protection", "SettingsDeleteProtection_Title": "Permanent Delete Protection",
"SettingsDiagnostics_Description": "For developers", "SettingsDiagnostics_Description": "For developers",
"SettingsDiagnostics_DiagnosticId_Description": "Share this ID with the developers when asked to get help for the issues you experience in Wino Mail.", "SettingsDiagnostics_DiagnosticId_Description": "Share this ID with the developers when asked to get help for the issues you experience in Wino Mail.",
@@ -566,6 +579,8 @@
"SettingsManageAccountSettings_Title": "Manage Account Settings", "SettingsManageAccountSettings_Title": "Manage Account Settings",
"SettingsManageAliases_Description": "See e-mail aliases assigned for this account, update or delete them.", "SettingsManageAliases_Description": "See e-mail aliases assigned for this account, update or delete them.",
"SettingsManageAliases_Title": "Aliases", "SettingsManageAliases_Title": "Aliases",
"SettingsEditAccountDetails_Title": "Edit Account Details",
"SettingsEditAccountDetails_Description": "Change account name, sender name and assign a new color if you like.",
"SettingsManageLink_Description": "Move items to add new link or remove existing link.", "SettingsManageLink_Description": "Move items to add new link or remove existing link.",
"SettingsManageLink_Title": "Manage Link", "SettingsManageLink_Title": "Manage Link",
"SettingsMarkAsRead_Description": "Change what should happen to the selected item.", "SettingsMarkAsRead_Description": "Change what should happen to the selected item.",
@@ -610,6 +625,11 @@
"SettingsShowPreviewText_Title": "Show Preview Text", "SettingsShowPreviewText_Title": "Show Preview Text",
"SettingsShowSenderPictures_Description": "Hide/show the thumbnail sender pictures.", "SettingsShowSenderPictures_Description": "Hide/show the thumbnail sender pictures.",
"SettingsShowSenderPictures_Title": "Show Sender Avatars", "SettingsShowSenderPictures_Title": "Show Sender Avatars",
"SettingsEnableGravatarAvatars_Title": "Gravatar",
"SettingsEnableGravatarAvatars_Description": "Use gravatar (if available) as sender picture",
"SettingsEnableFavicons_Title": "Domain icons (Favicons)",
"SettingsEnableFavicons_Description": "Use domain favicons (if available) as sender picture",
"SettingsMailList_ClearAvatarsCache_Button": "Clear cached avatars",
"SettingsSignature_AddCustomSignature_Button": "Add signature", "SettingsSignature_AddCustomSignature_Button": "Add signature",
"SettingsSignature_AddCustomSignature_Title": "Add custom signature", "SettingsSignature_AddCustomSignature_Title": "Add custom signature",
"SettingsSignature_DeleteSignature_Title": "Delete signature", "SettingsSignature_DeleteSignature_Title": "Delete signature",
@@ -631,6 +651,8 @@
"SettingsThreads_Title": "Conversation Threading", "SettingsThreads_Title": "Conversation Threading",
"SettingsUnlinkAccounts_Description": "Remove the link between accounts. his will not delete your accounts.", "SettingsUnlinkAccounts_Description": "Remove the link between accounts. his will not delete your accounts.",
"SettingsUnlinkAccounts_Title": "Unlink Accounts", "SettingsUnlinkAccounts_Title": "Unlink Accounts",
"SettingsMailRendering_ActionLabels_Title": "Action labels",
"SettingsMailRendering_ActionLabels_Description": "Show action labels.",
"SignatureDeleteDialog_Message": "Are you sure you want to delete \"{0}\" signature?", "SignatureDeleteDialog_Message": "Are you sure you want to delete \"{0}\" signature?",
"SignatureDeleteDialog_Title": "Delete signature", "SignatureDeleteDialog_Title": "Delete signature",
"SignatureEditorDialog_SignatureName_Placeholder": "Name your signature", "SignatureEditorDialog_SignatureName_Placeholder": "Name your signature",
@@ -676,7 +698,9 @@
"WinoUpgradeDescription": "Wino offers 3 accounts to start with for free. If you need more than 3 accounts, please upgrade", "WinoUpgradeDescription": "Wino offers 3 accounts to start with for free. If you need more than 3 accounts, please upgrade",
"WinoUpgradeMessage": "Upgrade to Unlimited Accounts", "WinoUpgradeMessage": "Upgrade to Unlimited Accounts",
"WinoUpgradeRemainingAccountsMessage": "{0} out of {1} free accounts used.", "WinoUpgradeRemainingAccountsMessage": "{0} out of {1} free accounts used.",
"Yesterday": "Yesterday" "Yesterday": "Yesterday",
"SettingsAppPreferences_EmailSyncInterval_Title": "Email sync interval",
"SettingsAppPreferences_EmailSyncInterval_Description": "Automatic email synchronization interval (minutes). This setting will be applied only after restarting Wino Mail."
} }

View File

@@ -4,9 +4,9 @@
"AccountAlias_Column_Verified": "Verificado", "AccountAlias_Column_Verified": "Verificado",
"AccountAlias_Disclaimer_FirstLine": "Wino solo puede importar alias de tus cuentas de Gmail.", "AccountAlias_Disclaimer_FirstLine": "Wino solo puede importar alias de tus cuentas de Gmail.",
"AccountAlias_Disclaimer_SecondLine": "Si quieres usar alias en cuentas Outlook o IMAP, puedes añadirlos manualmente.", "AccountAlias_Disclaimer_SecondLine": "Si quieres usar alias en cuentas Outlook o IMAP, puedes añadirlos manualmente.",
"AccountCacheReset_Title": "Account Cache Reset", "AccountCacheReset_Title": "Reiniciar Cache de Cuenta",
"AccountCacheReset_Message": "This account requires full re-sychronization to continue working. Please wait while Wino re-synchronizes your messages...", "AccountCacheReset_Message": "Esta cuenta requiere la resincronización completa para continuar trabajando. Por favor, espera mientras Wino sincroniza tus mensajes...",
"AccountContactNameYou": "You", "AccountContactNameYou": "Usted",
"AccountCreationDialog_Completed": "todo hecho", "AccountCreationDialog_Completed": "todo hecho",
"AccountCreationDialog_FetchingEvents": "Obteniendo eventos del calendario.", "AccountCreationDialog_FetchingEvents": "Obteniendo eventos del calendario.",
"AccountCreationDialog_FetchingProfileInformation": "Obteniendo información del perfil.", "AccountCreationDialog_FetchingProfileInformation": "Obteniendo información del perfil.",
@@ -22,6 +22,10 @@
"AccountPickerDialog_Title": "Elija una cuenta", "AccountPickerDialog_Title": "Elija una cuenta",
"AccountSettingsDialog_AccountName": "Nombre del remitente", "AccountSettingsDialog_AccountName": "Nombre del remitente",
"AccountSettingsDialog_AccountNamePlaceholder": "por ejemplo: Juan López", "AccountSettingsDialog_AccountNamePlaceholder": "por ejemplo: Juan López",
"AccountDetailsPage_Title": "Detalle de cuenta",
"AccountDetailsPage_Description": "Cambie el nombre de la cuenta en Wino y establezca el nombre deseado del remitente.",
"AccountDetailsPage_ColorPicker_Title": "Color de la cuenta",
"AccountDetailsPage_ColorPicker_Description": "Asigna un nuevo color de cuenta para colorear su símbolo en la lista.",
"AddHyperlink": "Añadir", "AddHyperlink": "Añadir",
"AppCloseBackgroundSynchronizationWarningTitle": "Sincronización en segundo plano", "AppCloseBackgroundSynchronizationWarningTitle": "Sincronización en segundo plano",
"AppCloseStartupLaunchDisabledWarningMessageFirstLine": "La aplicación no está configurada para iniciarse con Windows.", "AppCloseStartupLaunchDisabledWarningMessageFirstLine": "La aplicación no está configurada para iniciarse con Windows.",
@@ -184,7 +188,7 @@
"Exception_ImapClientPoolFailed": "Cola Cliente IMAP falló.", "Exception_ImapClientPoolFailed": "Cola Cliente IMAP falló.",
"Exception_InboxNotAvailable": "No se pudo configurar las carpetas de cuenta.", "Exception_InboxNotAvailable": "No se pudo configurar las carpetas de cuenta.",
"Exception_InvalidSystemFolderConfiguration": "La configuración de la carpeta del sistema no es válida. Verifica la configuración y vuelve a intentar.", "Exception_InvalidSystemFolderConfiguration": "La configuración de la carpeta del sistema no es válida. Verifica la configuración y vuelve a intentar.",
"Exception_InvalidMultiAccountMoveTarget": "You can't move multiple items that belong to different accounts in linked account.", "Exception_InvalidMultiAccountMoveTarget": "No puedes mover varios elementos que pertenecen a diferentes cuentas en la cuenta vinculada.",
"Exception_MailProcessing": "Este correo aún se está procesando. Inténtalo de nuevo en unos segundos.", "Exception_MailProcessing": "Este correo aún se está procesando. Inténtalo de nuevo en unos segundos.",
"Exception_MissingAlias": "Esta cuenta no tiene alias principal. Error al crear borrador.", "Exception_MissingAlias": "Esta cuenta no tiene alias principal. Error al crear borrador.",
"Exception_NullAssignedAccount": "La cuenta asignada es nula", "Exception_NullAssignedAccount": "La cuenta asignada es nula",
@@ -217,9 +221,9 @@
"GeneralTitle_Error": "Error", "GeneralTitle_Error": "Error",
"GeneralTitle_Info": "Información", "GeneralTitle_Info": "Información",
"GeneralTitle_Warning": "Advertencia", "GeneralTitle_Warning": "Advertencia",
"GmailServiceDisabled_Title": "Gmail Error", "GmailServiceDisabled_Title": "Error de Gmail",
"GmailServiceDisabled_Message": "Your Google Workspace account seems to be disabled for Gmail service. Please contact your administrator to enable Gmail service for your account.", "GmailServiceDisabled_Message": "Su cuenta de Google Workspace parece estar deshabilitada para el servicio de Gmail. Por favor, póngase en contacto con su administrador para habilitar el servicio de Gmail para su cuenta.",
"GmailArchiveFolderNameOverride": "Archive", "GmailArchiveFolderNameOverride": "Archivar",
"HoverActionOption_Archive": "Archivar", "HoverActionOption_Archive": "Archivar",
"HoverActionOption_Delete": "Eliminar", "HoverActionOption_Delete": "Eliminar",
"HoverActionOption_MoveJunk": "Mover a Correo no deseado", "HoverActionOption_MoveJunk": "Mover a Correo no deseado",
@@ -228,22 +232,22 @@
"ImageRenderingDisabled": "El procesamiento de imágenes está desactivado para este mensaje.", "ImageRenderingDisabled": "El procesamiento de imágenes está desactivado para este mensaje.",
"ImapAdvancedSetupDialog_AuthenticationMethod": "Método de autenticación", "ImapAdvancedSetupDialog_AuthenticationMethod": "Método de autenticación",
"ImapAdvancedSetupDialog_ConnectionSecurity": "Seguridad de la conexión", "ImapAdvancedSetupDialog_ConnectionSecurity": "Seguridad de la conexión",
"IMAPAdvancedSetupDialog_ValidationAuthMethodRequired": "Authentication method is required", "IMAPAdvancedSetupDialog_ValidationAuthMethodRequired": "El método de autenticación es obligatorio",
"IMAPAdvancedSetupDialog_ValidationConnectionSecurityRequired": "Connection security type is required", "IMAPAdvancedSetupDialog_ValidationConnectionSecurityRequired": "Se requiere el tipo de seguridad de la conexión",
"IMAPAdvancedSetupDialog_ValidationDisplayNameRequired": "Display name is required", "IMAPAdvancedSetupDialog_ValidationDisplayNameRequired": "Se necesita un nombre para mostrar",
"IMAPAdvancedSetupDialog_ValidationEmailInvalid": "Please enter a valid email address", "IMAPAdvancedSetupDialog_ValidationEmailInvalid": "Introduzca una dirección de correo electrónico válida",
"IMAPAdvancedSetupDialog_ValidationEmailRequired": "Email address is required", "IMAPAdvancedSetupDialog_ValidationEmailRequired": "Se requiere una dirección de email",
"IMAPAdvancedSetupDialog_ValidationErrorTitle": "Please check the following:", "IMAPAdvancedSetupDialog_ValidationErrorTitle": "Comprueba lo siguiente:",
"IMAPAdvancedSetupDialog_ValidationIncomingPortInvalid": "Incoming port must be between 1-65535", "IMAPAdvancedSetupDialog_ValidationIncomingPortInvalid": "Puerto entrante debe estar entre 1-65535",
"IMAPAdvancedSetupDialog_ValidationIncomingPortRequired": "Incoming server port is required", "IMAPAdvancedSetupDialog_ValidationIncomingPortRequired": "Se requiere puerto del servidor entrante",
"IMAPAdvancedSetupDialog_ValidationIncomingServerRequired": "Incoming server address is required", "IMAPAdvancedSetupDialog_ValidationIncomingServerRequired": "Se requiere una dirección del servidor entrante",
"IMAPAdvancedSetupDialog_ValidationOutgoingPasswordRequired": "Outgoing server password is required", "IMAPAdvancedSetupDialog_ValidationOutgoingPasswordRequired": "Se requiere la contraseña del servidor saliente",
"IMAPAdvancedSetupDialog_ValidationOutgoingPortInvalid": "Outgoing port must be between 1-65535", "IMAPAdvancedSetupDialog_ValidationOutgoingPortInvalid": "Puerto saliente debe estar entre 1-65535",
"IMAPAdvancedSetupDialog_ValidationOutgoingPortRequired": "Outgoing server port is required", "IMAPAdvancedSetupDialog_ValidationOutgoingPortRequired": "Se requiere puerto saliente del servidor",
"IMAPAdvancedSetupDialog_ValidationOutgoingServerRequired": "Outgoing server address is required", "IMAPAdvancedSetupDialog_ValidationOutgoingServerRequired": "Se requiere una dirección del servidor saliente",
"IMAPAdvancedSetupDialog_ValidationOutgoingUsernameRequired": "Outgoing server username is required", "IMAPAdvancedSetupDialog_ValidationOutgoingUsernameRequired": "Se requiere nombre de usuario del servidor saliente",
"IMAPAdvancedSetupDialog_ValidationPasswordRequired": "Password is required", "IMAPAdvancedSetupDialog_ValidationPasswordRequired": "La contraseña es obligatoria",
"IMAPAdvancedSetupDialog_ValidationUsernameRequired": "Username is required", "IMAPAdvancedSetupDialog_ValidationUsernameRequired": "Se requiere el nombre de usuario",
"ImapAuthenticationMethod_Auto": "Auto", "ImapAuthenticationMethod_Auto": "Auto",
"ImapAuthenticationMethod_CramMD5": "CRAM-MD5", "ImapAuthenticationMethod_CramMD5": "CRAM-MD5",
"ImapAuthenticationMethod_DigestMD5": "DIGEST-MD5", "ImapAuthenticationMethod_DigestMD5": "DIGEST-MD5",
@@ -256,6 +260,11 @@
"ImapConnectionSecurity_SslTls": "SSL/TLS", "ImapConnectionSecurity_SslTls": "SSL/TLS",
"ImapConnectionSecurity_StartTls": "STARTTLS", "ImapConnectionSecurity_StartTls": "STARTTLS",
"IMAPSetupDialog_AccountType": "Tipo de cuenta", "IMAPSetupDialog_AccountType": "Tipo de cuenta",
"IMAPSetupDialog_ValidationSuccess_Title": "Correcto",
"IMAPSetupDialog_ValidationSuccess_Message": "Validación correcta",
"IMAPSetupDialog_SaveImapSuccess_Title": "Correcto",
"IMAPSetupDialog_SaveImapSuccess_Message": "Ajustes IMAP guardados con éxito.",
"IMAPSetupDialog_ValidationFailed_Title": "La validación del servidor IMAP falló.",
"IMAPSetupDialog_CertificateAllowanceRequired_Row0": "El servidor requiere un protocolo de enlace SSL para continuar. Confirma los detalles del certificado a continuación.", "IMAPSetupDialog_CertificateAllowanceRequired_Row0": "El servidor requiere un protocolo de enlace SSL para continuar. Confirma los detalles del certificado a continuación.",
"IMAPSetupDialog_CertificateAllowanceRequired_Row1": "Permite el protocolo de enlace para continuar configurando tu cuenta.", "IMAPSetupDialog_CertificateAllowanceRequired_Row1": "Permite el protocolo de enlace para continuar configurando tu cuenta.",
"IMAPSetupDialog_CertificateDenied": "El usuario no ha autorizado el enlace con el certificado.", "IMAPSetupDialog_CertificateDenied": "El usuario no ha autorizado el enlace con el certificado.",
@@ -270,6 +279,8 @@
"IMAPSetupDialog_DisplayNamePlaceholder": "por ejemplo. Fulano Mengano", "IMAPSetupDialog_DisplayNamePlaceholder": "por ejemplo. Fulano Mengano",
"IMAPSetupDialog_IncomingMailServer": "Servidor de correo entrante", "IMAPSetupDialog_IncomingMailServer": "Servidor de correo entrante",
"IMAPSetupDialog_IncomingMailServerPort": "Puerto", "IMAPSetupDialog_IncomingMailServerPort": "Puerto",
"IMAPSetupDialog_IMAPSettings": "Configuración de servidor IMAP",
"IMAPSetupDialog_SMTPSettings": "Configuración de servidor SMTP",
"IMAPSetupDialog_MailAddress": "Dirección de correo", "IMAPSetupDialog_MailAddress": "Dirección de correo",
"IMAPSetupDialog_MailAddressPlaceholder": "alguien@ejemplo.com", "IMAPSetupDialog_MailAddressPlaceholder": "alguien@ejemplo.com",
"IMAPSetupDialog_OutgoingMailServer": "Servidor de correo saliente (SMTP)", "IMAPSetupDialog_OutgoingMailServer": "Servidor de correo saliente (SMTP)",
@@ -363,7 +374,7 @@
"Link": "Enlace", "Link": "Enlace",
"LinkedAccountsCreatePolicyMessage": "debes tener al menos 2 cuentas para crear el enlace\nenlace se eliminará al guardar", "LinkedAccountsCreatePolicyMessage": "debes tener al menos 2 cuentas para crear el enlace\nenlace se eliminará al guardar",
"LinkedAccountsTitle": "Cuentas Vinculadas", "LinkedAccountsTitle": "Cuentas Vinculadas",
"MailItemNoSubject": "No subject", "MailItemNoSubject": "Sin asunto",
"MailOperation_AlwaysMoveFocused": "Siempre Mover a Importantes", "MailOperation_AlwaysMoveFocused": "Siempre Mover a Importantes",
"MailOperation_AlwaysMoveOther": "Siempre Mover a Otros", "MailOperation_AlwaysMoveOther": "Siempre Mover a Otros",
"MailOperation_Archive": "Archivar", "MailOperation_Archive": "Archivar",
@@ -390,7 +401,7 @@
"MailOperation_SaveAs": "Guardar Como", "MailOperation_SaveAs": "Guardar Como",
"MailOperation_SetFlag": "Establecer marca", "MailOperation_SetFlag": "Establecer marca",
"MailOperation_Unarchive": "Desarchivar", "MailOperation_Unarchive": "Desarchivar",
"MailOperation_ViewMessageSource": "View message source", "MailOperation_ViewMessageSource": "Ver fuente del mensaje",
"MailOperation_Zoom": "Zoom", "MailOperation_Zoom": "Zoom",
"MailsSelected": "{0} artículo(s) seleccionado(s)", "MailsSelected": "{0} artículo(s) seleccionado(s)",
"MarkFlagUnflag": "Marcar como marcado/desmarcado", "MarkFlagUnflag": "Marcar como marcado/desmarcado",
@@ -407,7 +418,7 @@
"MergedAccountCommonFolderSent": "Enviados", "MergedAccountCommonFolderSent": "Enviados",
"MergedAccountCommonFolderTrash": "Eliminados", "MergedAccountCommonFolderTrash": "Eliminados",
"MergedAccountsAvailableAccountsTitle": "Cuentas Disponibles", "MergedAccountsAvailableAccountsTitle": "Cuentas Disponibles",
"MessageSourceDialog_Title": "Message source", "MessageSourceDialog_Title": "Origen de mensajes",
"More": "Más", "More": "Más",
"MoreFolderNameOverride": "Más", "MoreFolderNameOverride": "Más",
"MoveMailDialog_InvalidFolderMessage": "La carpeta {0} no es válida para este correo.", "MoveMailDialog_InvalidFolderMessage": "La carpeta {0} no es válida para este correo.",
@@ -423,9 +434,9 @@
"Notifications_MultipleNotificationsTitle": "Mensajes nuevos", "Notifications_MultipleNotificationsTitle": "Mensajes nuevos",
"Notifications_WinoUpdatedMessage": "Comprobar nueva versión {0}", "Notifications_WinoUpdatedMessage": "Comprobar nueva versión {0}",
"Notifications_WinoUpdatedTitle": "Wino Mail ha sido actualizado.", "Notifications_WinoUpdatedTitle": "Wino Mail ha sido actualizado.",
"OnlineSearchFailed_Message": "Failed to perform search\n{0}\n\nListing offline mails.", "OnlineSearchFailed_Message": "Error al realizar la búsqueda\n{0}\n\nLista de correos sin conexión.",
"OnlineSearchTry_Line1": "Can't find what you are looking for?", "OnlineSearchTry_Line1": "¿No encuentra lo que busca?",
"OnlineSearchTry_Line2": "Try online search.", "OnlineSearchTry_Line2": "Prueba la búsqueda en línea.",
"Other": "Otro", "Other": "Otro",
"PaneLengthOption_Default": "Por defecto", "PaneLengthOption_Default": "Por defecto",
"PaneLengthOption_ExtraLarge": "Extra grande", "PaneLengthOption_ExtraLarge": "Extra grande",
@@ -437,17 +448,17 @@
"PreparingFoldersMessage": "Preparando carpetas", "PreparingFoldersMessage": "Preparando carpetas",
"ProtocolLogAvailable_Message": "Los registros de protocolo están disponibles para el diagnóstico.", "ProtocolLogAvailable_Message": "Los registros de protocolo están disponibles para el diagnóstico.",
"ProviderDetail_Gmail_Description": "Cuenta de Google", "ProviderDetail_Gmail_Description": "Cuenta de Google",
"ProviderDetail_iCloud_Description": "Apple iCloud Account", "ProviderDetail_iCloud_Description": "Cuenta de Apple iCloud",
"ProviderDetail_iCloud_Title": "iCloud", "ProviderDetail_iCloud_Title": "iCloud",
"ProviderDetail_IMAP_Description": "Servidor IMAP/SMTP personalizado", "ProviderDetail_IMAP_Description": "Servidor IMAP/SMTP personalizado",
"ProviderDetail_IMAP_Title": "Servidor IMAP", "ProviderDetail_IMAP_Title": "Servidor IMAP",
"ProviderDetail_Yahoo_Description": "Yahoo Account", "ProviderDetail_Yahoo_Description": "Cuenta de Yahoo",
"ProviderDetail_Yahoo_Title": "Yahoo Mail", "ProviderDetail_Yahoo_Title": "Correo Yahoo",
"QuickEventDialog_EventName": "Event name", "QuickEventDialog_EventName": "Nombre del evento",
"QuickEventDialog_IsAllDay": "All day", "QuickEventDialog_IsAllDay": "Todo el día",
"QuickEventDialog_Location": "Location", "QuickEventDialog_Location": "Ubicación",
"QuickEventDialog_RemindMe": "Remind me", "QuickEventDialog_RemindMe": "Recuerdame",
"QuickEventDialogMoreDetailsButtonText": "More details", "QuickEventDialogMoreDetailsButtonText": "Más detalles",
"Reader_SaveAllAttachmentButtonText": "Guardar todos los adjuntos", "Reader_SaveAllAttachmentButtonText": "Guardar todos los adjuntos",
"Results": "Resultados", "Results": "Resultados",
"Right": "Derecha", "Right": "Derecha",
@@ -455,6 +466,8 @@
"SearchingIn": "Buscando en", "SearchingIn": "Buscando en",
"SearchPivotName": "Resultados", "SearchPivotName": "Resultados",
"SettingConfigureSpecialFolders_Button": "Configurar", "SettingConfigureSpecialFolders_Button": "Configurar",
"SettingsEditAccountDetails_IMAPConfiguration_Title": "Configuración IMAP/SMTP",
"SettingsEditAccountDetails_IMAPConfiguration_Description": "Cambie la configuración del servidor entrante/saliente.",
"SettingsAbout_Description": "Conoce más sobre Wino.", "SettingsAbout_Description": "Conoce más sobre Wino.",
"SettingsAbout_Title": "Acerca de", "SettingsAbout_Title": "Acerca de",
"SettingsAboutGithub_Description": "Ir al rastreador de problemas en el repositorio de GitHub.", "SettingsAboutGithub_Description": "Ir al rastreador de problemas en el repositorio de GitHub.",
@@ -473,24 +486,24 @@
"SettingsAppPreferences_CloseBehavior_Description": "¿Qué ocurre cuando cierras la aplicación?", "SettingsAppPreferences_CloseBehavior_Description": "¿Qué ocurre cuando cierras la aplicación?",
"SettingsAppPreferences_CloseBehavior_Title": "Cierre de la aplicación", "SettingsAppPreferences_CloseBehavior_Title": "Cierre de la aplicación",
"SettingsAppPreferences_Description": "Ajustes generales de Wino Mail.", "SettingsAppPreferences_Description": "Ajustes generales de Wino Mail.",
"SettingsAppPreferences_SearchMode_Description": "Set whether Wino should check fetched mails first while doing a search or ask your mail server online. Local search is always faster and you can always do an online search if your mail is not in the results.", "SettingsAppPreferences_SearchMode_Description": "Establezca si Wino debería comprobar primero los correos obtenidos realizando una búsqueda o pregunta al servidor de correo en línea. La búsqueda local es más rápida y siempre puede hacer una búsqueda en línea si su correo no está en los resultados.",
"SettingsAppPreferences_SearchMode_Local": "Local", "SettingsAppPreferences_SearchMode_Local": "Local",
"SettingsAppPreferences_SearchMode_Online": "Online", "SettingsAppPreferences_SearchMode_Online": "Conectado",
"SettingsAppPreferences_SearchMode_Title": "Default search mode", "SettingsAppPreferences_SearchMode_Title": "Modo de búsqueda predeterminado",
"SettingsAppPreferences_ServerBackgroundingMode_Invisible_Description": "Wino Mail will keep running in the background. You will be notified as new mails arrive.", "SettingsAppPreferences_ServerBackgroundingMode_Invisible_Description": "Wino Mail seguirá funcionando en segundo plano. Se le notificará cuando lleguen nuevos correos.",
"SettingsAppPreferences_ServerBackgroundingMode_Invisible_Title": "Run in the background", "SettingsAppPreferences_ServerBackgroundingMode_Invisible_Title": "Ejecutarse en segundo plano",
"SettingsAppPreferences_ServerBackgroundingMode_MinimizeTray_Description": "Wino Mail will keep running on the system tray. Available to launch by clicking on an icon. You will be notified as new mails arrive.", "SettingsAppPreferences_ServerBackgroundingMode_MinimizeTray_Description": "Wino Mail funcionará en la bandeja del sistema. Se lanzará haciendo clic en un icono. Se notificará como llegan nuevos correos.",
"SettingsAppPreferences_ServerBackgroundingMode_MinimizeTray_Title": "Minimize to system tray", "SettingsAppPreferences_ServerBackgroundingMode_MinimizeTray_Title": "Minimizar a la bandeja del sistema",
"SettingsAppPreferences_ServerBackgroundingMode_Terminate_Description": "Wino Mail will not keep running anywhere. You will not be notified as new mails arrive. Launch Wino Mail again to continue mail synchronization.", "SettingsAppPreferences_ServerBackgroundingMode_Terminate_Description": "Wino Mail no funcionará en ningún lugar. No se notificará como llegan nuevos correos. Inicie Wino Mail de nuevo para continuar la sincronización de correo.",
"SettingsAppPreferences_ServerBackgroundingMode_Terminate_Title": "Terminate", "SettingsAppPreferences_ServerBackgroundingMode_Terminate_Title": "Terminar",
"SettingsAppPreferences_StartupBehavior_Description": "Allow Wino Mail to launch minimized when Windows starts. Always allow it to receive notifications.", "SettingsAppPreferences_StartupBehavior_Description": "Permitir que Wino Mail minimizado cuando Windows se inicie. Permitir siempre recibir notificaciones.",
"SettingsAppPreferences_StartupBehavior_Disable": "Disable", "SettingsAppPreferences_StartupBehavior_Disable": "Deshabilitar",
"SettingsAppPreferences_StartupBehavior_Disabled": "Wino Mail will not be launched on Windows startup. This will cause you to miss notifications when you restart your computer.", "SettingsAppPreferences_StartupBehavior_Disabled": "Wino Mail no se iniciará al arrancar Windows. Esto le hará perder las notificaciones cuando reinicie su equipo.",
"SettingsAppPreferences_StartupBehavior_DisabledByPolicy": "Your administrator or group policies disabled running applications on startup. Thus, Wino Mail can't be set to launch on Windows startup.", "SettingsAppPreferences_StartupBehavior_DisabledByPolicy": "Su política de administrador o grupo ha deshabilitado aplicaciones al iniciar. Por lo tanto, Wino Mail no se puede ejecutar al iniciar Windows.",
"SettingsAppPreferences_StartupBehavior_DisabledByUser": "Please go to Task Manager -> Startup tab to allow Wino Mail to launch on Windows startup.", "SettingsAppPreferences_StartupBehavior_DisabledByUser": "Vaya a la pestaña Administrador de tareas -> Inicio para permitir que Wino Mail inicie en el arranque Windows.",
"SettingsAppPreferences_StartupBehavior_Enable": "Enable", "SettingsAppPreferences_StartupBehavior_Enable": "Activar",
"SettingsAppPreferences_StartupBehavior_Enabled": "Wino Mail successfully set to be launched in the background on Windows startup.", "SettingsAppPreferences_StartupBehavior_Enabled": "Wino Mail configurado correctamente para ser lanzado en segundo plano al inicio de Windows.",
"SettingsAppPreferences_StartupBehavior_FatalError": "Fatal error occurred while changing the startup mode for Wino Mail.", "SettingsAppPreferences_StartupBehavior_FatalError": "Error fatal al cambiar el modo de inicio para Wino Mail.",
"SettingsAppPreferences_StartupBehavior_Title": "Ejecutar minimizado al iniciar Windows", "SettingsAppPreferences_StartupBehavior_Title": "Ejecutar minimizado al iniciar Windows",
"SettingsAppPreferences_Title": "Configuración de la aplicación", "SettingsAppPreferences_Title": "Configuración de la aplicación",
"SettingsAutoSelectNextItem_Description": "Seleccione el siguiente elemento después de eliminar o mover un correo.", "SettingsAutoSelectNextItem_Description": "Seleccione el siguiente elemento después de eliminar o mover un correo.",
@@ -511,8 +524,8 @@
"SettingsDeleteProtection_Description": "¿Debería Wino pedirte confirmación cada vez que intentas eliminar un correo usando las teclas Shift + Supr?", "SettingsDeleteProtection_Description": "¿Debería Wino pedirte confirmación cada vez que intentas eliminar un correo usando las teclas Shift + Supr?",
"SettingsDeleteProtection_Title": "Protección de Eliminación Permanente", "SettingsDeleteProtection_Title": "Protección de Eliminación Permanente",
"SettingsDiagnostics_Description": "Para desarrolladores", "SettingsDiagnostics_Description": "Para desarrolladores",
"SettingsDiagnostics_DiagnosticId_Description": "Share this ID with the developers when asked to get help for the issues you experience in Wino Mail.", "SettingsDiagnostics_DiagnosticId_Description": "Comparte este ID con los desarrolladores cuando se les pida ayuda para los problemas que experimentas en Wino Mail.",
"SettingsDiagnostics_DiagnosticId_Title": "Diagnostic ID", "SettingsDiagnostics_DiagnosticId_Title": "ID de Diagnóstico",
"SettingsDiagnostics_Title": "Diagnósticos", "SettingsDiagnostics_Title": "Diagnósticos",
"SettingsDiscord_Description": "Recibe actualizaciones regulares sobre el desarrollo, únete a las discusiones sobre los avances y proporciona comentarios.", "SettingsDiscord_Description": "Recibe actualizaciones regulares sobre el desarrollo, únete a las discusiones sobre los avances y proporciona comentarios.",
"SettingsDiscord_Title": "Canal de Discord", "SettingsDiscord_Title": "Canal de Discord",
@@ -558,14 +571,16 @@
"SettingsLoadImages_Title": "Cargar imágenes automáticamente", "SettingsLoadImages_Title": "Cargar imágenes automáticamente",
"SettingsLoadPlaintextLinks_Title": "Convierte los enlaces de texto plano a interactivos", "SettingsLoadPlaintextLinks_Title": "Convierte los enlaces de texto plano a interactivos",
"SettingsLoadStyles_Title": "Cargar estilos automáticamente", "SettingsLoadStyles_Title": "Cargar estilos automáticamente",
"SettingsMailListActionBar_Description": "Hide/show action bar at top of message list.", "SettingsMailListActionBar_Description": "Ocultar/Mostrar barra de acción en la parte superior de la lista de mensajes.",
"SettingsMailListActionBar_Title": "Show mail list actions", "SettingsMailListActionBar_Title": "Mostrar acciones de la lista de correos",
"SettingsMailSpacing_Description": "Ajustar el espacio para listar los correos.", "SettingsMailSpacing_Description": "Ajustar el espacio para listar los correos.",
"SettingsMailSpacing_Title": "Espacio de Correo", "SettingsMailSpacing_Title": "Espacio de Correo",
"SettingsManageAccountSettings_Description": "Notificaciones, firmas, sincronización y otros ajustes por cuenta.", "SettingsManageAccountSettings_Description": "Notificaciones, firmas, sincronización y otros ajustes por cuenta.",
"SettingsManageAccountSettings_Title": "Administrar ajustes de cuenta", "SettingsManageAccountSettings_Title": "Administrar ajustes de cuenta",
"SettingsManageAliases_Description": "Comprueba, actualiza o elimina los alias de correo asociados a esta cuenta.", "SettingsManageAliases_Description": "Comprueba, actualiza o elimina los alias de correo asociados a esta cuenta.",
"SettingsManageAliases_Title": "Alias", "SettingsManageAliases_Title": "Alias",
"SettingsEditAccountDetails_Title": "Editar Detalles de Cuenta",
"SettingsEditAccountDetails_Description": "Cambie el nombre de la cuenta, nombre del remitente y asigne un nuevo color si lo desea.",
"SettingsManageLink_Description": "Mover elementos para añadir un nuevo enlace o eliminar el enlace existente.", "SettingsManageLink_Description": "Mover elementos para añadir un nuevo enlace o eliminar el enlace existente.",
"SettingsManageLink_Title": "Administrar enlaces", "SettingsManageLink_Title": "Administrar enlaces",
"SettingsMarkAsRead_Description": "Cambiar lo que debería pasar con el elemento seleccionado.", "SettingsMarkAsRead_Description": "Cambiar lo que debería pasar con el elemento seleccionado.",
@@ -579,11 +594,11 @@
"SettingsNoAccountSetupMessage": "Aún no has configurado ninguna cuenta.", "SettingsNoAccountSetupMessage": "Aún no has configurado ninguna cuenta.",
"SettingsNotifications_Description": "Activar o desactivar notificaciones para esta cuenta.", "SettingsNotifications_Description": "Activar o desactivar notificaciones para esta cuenta.",
"SettingsNotifications_Title": "Notificaciones", "SettingsNotifications_Title": "Notificaciones",
"SettingsNotificationsAndTaskbar_Description": "Change whether notifications should be displayed and taskbar badge for this account.", "SettingsNotificationsAndTaskbar_Description": "Cambiar si las notificaciones deben mostrarse y la insignia de la barra de tareas para esta cuenta.",
"SettingsNotificationsAndTaskbar_Title": "Notifications & Taskbar", "SettingsNotificationsAndTaskbar_Title": "Notificaciones y Barra de tareas",
"SettingsOptions_Title": "Ajustes", "SettingsOptions_Title": "Ajustes",
"SettingsPaneLengthReset_Description": "Reset the size of the mail list to original if you have issues with it.", "SettingsPaneLengthReset_Description": "Restablecer el tamaño de la lista de correo a original si tiene problemas.",
"SettingsPaneLengthReset_Title": "Reset Mail List Size", "SettingsPaneLengthReset_Title": "Resetear tamaño de lista de correo",
"SettingsPaypal_Description": "Muestre mucho más amor ❤️ Todas las donaciones se agradecen.", "SettingsPaypal_Description": "Muestre mucho más amor ❤️ Todas las donaciones se agradecen.",
"SettingsPaypal_Title": "Dona vía PayPal", "SettingsPaypal_Title": "Dona vía PayPal",
"SettingsPersonalization_Description": "Cambia la apariencia de Wino a tu gusto.", "SettingsPersonalization_Description": "Cambia la apariencia de Wino a tu gusto.",
@@ -606,10 +621,15 @@
"SettingsReorderAccounts_Title": "Reordenar cuentas", "SettingsReorderAccounts_Title": "Reordenar cuentas",
"SettingsSemanticZoom_Description": "Esto le permitirá hacer clic en los encabezados de la lista de mensajes e ir a una fecha específica", "SettingsSemanticZoom_Description": "Esto le permitirá hacer clic en los encabezados de la lista de mensajes e ir a una fecha específica",
"SettingsSemanticZoom_Title": "Zoom semántico para los encabezados de fechas", "SettingsSemanticZoom_Title": "Zoom semántico para los encabezados de fechas",
"SettingsShowPreviewText_Description": "Hide/show the preview text.", "SettingsShowPreviewText_Description": "Ocultar/mostrar texto de vista previa.",
"SettingsShowPreviewText_Title": "Mostrar texto de vista previa", "SettingsShowPreviewText_Title": "Mostrar texto de vista previa",
"SettingsShowSenderPictures_Description": "Ocultar/mostrar imágenes del remitente en miniatura.", "SettingsShowSenderPictures_Description": "Ocultar/mostrar imágenes del remitente en miniatura.",
"SettingsShowSenderPictures_Title": "Mostrar Avatares de Remitente", "SettingsShowSenderPictures_Title": "Mostrar Avatares de Remitente",
"SettingsEnableGravatarAvatars_Title": "Gravatar",
"SettingsEnableGravatarAvatars_Description": "Usar gravatar (si está disponible) como imagen del remitente",
"SettingsEnableFavicons_Title": "Iconos de dominio (Faviconos)",
"SettingsEnableFavicons_Description": "Usar favicons de dominio (si está disponible) como imagen del remitente",
"SettingsMailList_ClearAvatarsCache_Button": "Limpiar avatares en caché",
"SettingsSignature_AddCustomSignature_Button": "Añadir firma", "SettingsSignature_AddCustomSignature_Button": "Añadir firma",
"SettingsSignature_AddCustomSignature_Title": "Añadir firma personalizada", "SettingsSignature_AddCustomSignature_Title": "Añadir firma personalizada",
"SettingsSignature_DeleteSignature_Title": "Eliminar firma", "SettingsSignature_DeleteSignature_Title": "Eliminar firma",
@@ -625,12 +645,14 @@
"SettingsStartupItem_Title": "Elemento de Inicio", "SettingsStartupItem_Title": "Elemento de Inicio",
"SettingsStore_Description": "Mostrar un poco de amor ❤️", "SettingsStore_Description": "Mostrar un poco de amor ❤️",
"SettingsStore_Title": "Valorar en la tienda", "SettingsStore_Title": "Valorar en la tienda",
"SettingsTaskbarBadge_Description": "Include unread mail count in taskbar icon.", "SettingsTaskbarBadge_Description": "Incluye conteo de correo no leído en el icono de la barra de tareas.",
"SettingsTaskbarBadge_Title": "Taskbar Badge", "SettingsTaskbarBadge_Title": "Insignia de la barra de tareas",
"SettingsThreads_Description": "Organizar mensajes en hilos de conversación.", "SettingsThreads_Description": "Organizar mensajes en hilos de conversación.",
"SettingsThreads_Title": "Hilos de conversación", "SettingsThreads_Title": "Hilos de conversación",
"SettingsUnlinkAccounts_Description": "Remove the link between accounts. his will not delete your accounts.", "SettingsUnlinkAccounts_Description": "Eliminar el enlace entre cuentas. No eliminará sus cuentas.",
"SettingsUnlinkAccounts_Title": "Desvincular Cuentas", "SettingsUnlinkAccounts_Title": "Desvincular Cuentas",
"SettingsMailRendering_ActionLabels_Title": "Etiquetas de acción",
"SettingsMailRendering_ActionLabels_Description": "Mostrar etiquetas de acción.",
"SignatureDeleteDialog_Message": "¿Seguro que quieres eliminar la firma \"{0}\"?", "SignatureDeleteDialog_Message": "¿Seguro que quieres eliminar la firma \"{0}\"?",
"SignatureDeleteDialog_Title": "Eliminar firma", "SignatureDeleteDialog_Title": "Eliminar firma",
"SignatureEditorDialog_SignatureName_Placeholder": "Ponle un nombre a tu firma", "SignatureEditorDialog_SignatureName_Placeholder": "Ponle un nombre a tu firma",
@@ -662,10 +684,10 @@
"SystemFolderConfigSetupSuccess_Message": "Carpetas del sistema configuradas correctamente.", "SystemFolderConfigSetupSuccess_Message": "Carpetas del sistema configuradas correctamente.",
"SystemFolderConfigSetupSuccess_Title": "Configurar Carpetas del Sistema", "SystemFolderConfigSetupSuccess_Title": "Configurar Carpetas del Sistema",
"TestingImapConnectionMessage": "Probando conexión con el servidor...", "TestingImapConnectionMessage": "Probando conexión con el servidor...",
"TitleBarServerDisconnectedButton_Description": "Wino is disconnected from the network. Click reconnect to restore connection.", "TitleBarServerDisconnectedButton_Description": "Wino está desconectado de la red. Haga clic en reconectar para restaurar la conexión.",
"TitleBarServerDisconnectedButton_Title": "no connection", "TitleBarServerDisconnectedButton_Title": "sin conexión",
"TitleBarServerReconnectButton_Title": "reconnect", "TitleBarServerReconnectButton_Title": "re-conectar",
"TitleBarServerReconnectingButton_Title": "connecting", "TitleBarServerReconnectingButton_Title": "conectando",
"Today": "Hoy", "Today": "Hoy",
"UnknownAddress": "dirección desconocida", "UnknownAddress": "dirección desconocida",
"UnknownDateHeader": "Fecha desconocida", "UnknownDateHeader": "Fecha desconocida",
@@ -676,7 +698,9 @@
"WinoUpgradeDescription": "Wino ofrece 3 cuentas para empezar gratis. Si necesitas más de 3 cuentas por favor actualiza", "WinoUpgradeDescription": "Wino ofrece 3 cuentas para empezar gratis. Si necesitas más de 3 cuentas por favor actualiza",
"WinoUpgradeMessage": "Actualizar a Cuentas Ilimitadas", "WinoUpgradeMessage": "Actualizar a Cuentas Ilimitadas",
"WinoUpgradeRemainingAccountsMessage": "{0} de {1} cuentas gratuitas usadas.", "WinoUpgradeRemainingAccountsMessage": "{0} de {1} cuentas gratuitas usadas.",
"Yesterday": "Ayer" "Yesterday": "Ayer",
"SettingsAppPreferences_EmailSyncInterval_Title": "Email sync interval",
"SettingsAppPreferences_EmailSyncInterval_Description": "Automatic email synchronization interval (minutes). This setting will be applied only after restarting Wino Mail."
} }

View File

@@ -22,6 +22,10 @@
"AccountPickerDialog_Title": "Valitse tili", "AccountPickerDialog_Title": "Valitse tili",
"AccountSettingsDialog_AccountName": "Lähettäjän nimi", "AccountSettingsDialog_AccountName": "Lähettäjän nimi",
"AccountSettingsDialog_AccountNamePlaceholder": "esim. Matti Meikäläinen", "AccountSettingsDialog_AccountNamePlaceholder": "esim. Matti Meikäläinen",
"AccountDetailsPage_Title": "Account info",
"AccountDetailsPage_Description": "Change the name of the account in Wino and set desired sender name.",
"AccountDetailsPage_ColorPicker_Title": "Account color",
"AccountDetailsPage_ColorPicker_Description": "Assign a new account color to colorize its symbol in the list.",
"AddHyperlink": "Lisää", "AddHyperlink": "Lisää",
"AppCloseBackgroundSynchronizationWarningTitle": "Background Synchronization", "AppCloseBackgroundSynchronizationWarningTitle": "Background Synchronization",
"AppCloseStartupLaunchDisabledWarningMessageFirstLine": "Application has not been set to launch on Windows startup.", "AppCloseStartupLaunchDisabledWarningMessageFirstLine": "Application has not been set to launch on Windows startup.",
@@ -256,6 +260,11 @@
"ImapConnectionSecurity_SslTls": "SSL/TLS", "ImapConnectionSecurity_SslTls": "SSL/TLS",
"ImapConnectionSecurity_StartTls": "STARTTLS", "ImapConnectionSecurity_StartTls": "STARTTLS",
"IMAPSetupDialog_AccountType": "Account type", "IMAPSetupDialog_AccountType": "Account type",
"IMAPSetupDialog_ValidationSuccess_Title": "Success",
"IMAPSetupDialog_ValidationSuccess_Message": "Validation successful",
"IMAPSetupDialog_SaveImapSuccess_Title": "Success",
"IMAPSetupDialog_SaveImapSuccess_Message": "IMAP settings saved successfuly.",
"IMAPSetupDialog_ValidationFailed_Title": "IMAP Server validation failed.",
"IMAPSetupDialog_CertificateAllowanceRequired_Row0": "This server is requesting a SSL handshake to continue. Please confirm the certificate details below.", "IMAPSetupDialog_CertificateAllowanceRequired_Row0": "This server is requesting a SSL handshake to continue. Please confirm the certificate details below.",
"IMAPSetupDialog_CertificateAllowanceRequired_Row1": "Allow the handshake to continue setting up your account.", "IMAPSetupDialog_CertificateAllowanceRequired_Row1": "Allow the handshake to continue setting up your account.",
"IMAPSetupDialog_CertificateDenied": "User didn't authorize the handshake with the certificate.", "IMAPSetupDialog_CertificateDenied": "User didn't authorize the handshake with the certificate.",
@@ -270,6 +279,8 @@
"IMAPSetupDialog_DisplayNamePlaceholder": "eg. John Doe", "IMAPSetupDialog_DisplayNamePlaceholder": "eg. John Doe",
"IMAPSetupDialog_IncomingMailServer": "Incoming mail server", "IMAPSetupDialog_IncomingMailServer": "Incoming mail server",
"IMAPSetupDialog_IncomingMailServerPort": "Port", "IMAPSetupDialog_IncomingMailServerPort": "Port",
"IMAPSetupDialog_IMAPSettings": "IMAP Server Settings",
"IMAPSetupDialog_SMTPSettings": "SMTP Server Settings",
"IMAPSetupDialog_MailAddress": "Email address", "IMAPSetupDialog_MailAddress": "Email address",
"IMAPSetupDialog_MailAddressPlaceholder": "someone@example.com", "IMAPSetupDialog_MailAddressPlaceholder": "someone@example.com",
"IMAPSetupDialog_OutgoingMailServer": "Outgoing (SMTP) mail server", "IMAPSetupDialog_OutgoingMailServer": "Outgoing (SMTP) mail server",
@@ -455,6 +466,8 @@
"SearchingIn": "Searching in", "SearchingIn": "Searching in",
"SearchPivotName": "Results", "SearchPivotName": "Results",
"SettingConfigureSpecialFolders_Button": "Configure", "SettingConfigureSpecialFolders_Button": "Configure",
"SettingsEditAccountDetails_IMAPConfiguration_Title": "IMAP/SMTP Configuration",
"SettingsEditAccountDetails_IMAPConfiguration_Description": "Change your incoming/outgoing server settings.",
"SettingsAbout_Description": "Learn more about Wino.", "SettingsAbout_Description": "Learn more about Wino.",
"SettingsAbout_Title": "About", "SettingsAbout_Title": "About",
"SettingsAboutGithub_Description": "Go to issue tracker GitHub repository.", "SettingsAboutGithub_Description": "Go to issue tracker GitHub repository.",
@@ -508,7 +521,7 @@
"SettingsCustomTheme_Title": "Custom Theme", "SettingsCustomTheme_Title": "Custom Theme",
"SettingsDeleteAccount_Description": "Delete all e-mails and credentials associated with this account.", "SettingsDeleteAccount_Description": "Delete all e-mails and credentials associated with this account.",
"SettingsDeleteAccount_Title": "Delete this account", "SettingsDeleteAccount_Title": "Delete this account",
"SettingsDeleteProtection_Description": "Should Wino ask you for comfirmation every time you try to permanently delete a mail using Shift + Del keys?", "SettingsDeleteProtection_Description": "Should Wino ask you for confirmation every time you try to permanently delete a mail using Shift + Del keys?",
"SettingsDeleteProtection_Title": "Permanent Delete Protection", "SettingsDeleteProtection_Title": "Permanent Delete Protection",
"SettingsDiagnostics_Description": "For developers", "SettingsDiagnostics_Description": "For developers",
"SettingsDiagnostics_DiagnosticId_Description": "Share this ID with the developers when asked to get help for the issues you experience in Wino Mail.", "SettingsDiagnostics_DiagnosticId_Description": "Share this ID with the developers when asked to get help for the issues you experience in Wino Mail.",
@@ -566,6 +579,8 @@
"SettingsManageAccountSettings_Title": "Manage Account Settings", "SettingsManageAccountSettings_Title": "Manage Account Settings",
"SettingsManageAliases_Description": "See e-mail aliases assigned for this account, update or delete them.", "SettingsManageAliases_Description": "See e-mail aliases assigned for this account, update or delete them.",
"SettingsManageAliases_Title": "Aliases", "SettingsManageAliases_Title": "Aliases",
"SettingsEditAccountDetails_Title": "Edit Account Details",
"SettingsEditAccountDetails_Description": "Change account name, sender name and assign a new color if you like.",
"SettingsManageLink_Description": "Move items to add new link or remove existing link.", "SettingsManageLink_Description": "Move items to add new link or remove existing link.",
"SettingsManageLink_Title": "Manage Link", "SettingsManageLink_Title": "Manage Link",
"SettingsMarkAsRead_Description": "Change what should happen to the selected item.", "SettingsMarkAsRead_Description": "Change what should happen to the selected item.",
@@ -610,6 +625,11 @@
"SettingsShowPreviewText_Title": "Show Preview Text", "SettingsShowPreviewText_Title": "Show Preview Text",
"SettingsShowSenderPictures_Description": "Hide/show the thumbnail sender pictures.", "SettingsShowSenderPictures_Description": "Hide/show the thumbnail sender pictures.",
"SettingsShowSenderPictures_Title": "Show Sender Avatars", "SettingsShowSenderPictures_Title": "Show Sender Avatars",
"SettingsEnableGravatarAvatars_Title": "Gravatar",
"SettingsEnableGravatarAvatars_Description": "Use gravatar (if available) as sender picture",
"SettingsEnableFavicons_Title": "Domain icons (Favicons)",
"SettingsEnableFavicons_Description": "Use domain favicons (if available) as sender picture",
"SettingsMailList_ClearAvatarsCache_Button": "Clear cached avatars",
"SettingsSignature_AddCustomSignature_Button": "Add signature", "SettingsSignature_AddCustomSignature_Button": "Add signature",
"SettingsSignature_AddCustomSignature_Title": "Add custom signature", "SettingsSignature_AddCustomSignature_Title": "Add custom signature",
"SettingsSignature_DeleteSignature_Title": "Delete signature", "SettingsSignature_DeleteSignature_Title": "Delete signature",
@@ -631,6 +651,8 @@
"SettingsThreads_Title": "Conversation Threading", "SettingsThreads_Title": "Conversation Threading",
"SettingsUnlinkAccounts_Description": "Remove the link between accounts. his will not delete your accounts.", "SettingsUnlinkAccounts_Description": "Remove the link between accounts. his will not delete your accounts.",
"SettingsUnlinkAccounts_Title": "Unlink Accounts", "SettingsUnlinkAccounts_Title": "Unlink Accounts",
"SettingsMailRendering_ActionLabels_Title": "Action labels",
"SettingsMailRendering_ActionLabels_Description": "Show action labels.",
"SignatureDeleteDialog_Message": "Are you sure you want to delete \"{0}\" signature?", "SignatureDeleteDialog_Message": "Are you sure you want to delete \"{0}\" signature?",
"SignatureDeleteDialog_Title": "Delete signature", "SignatureDeleteDialog_Title": "Delete signature",
"SignatureEditorDialog_SignatureName_Placeholder": "Name your signature", "SignatureEditorDialog_SignatureName_Placeholder": "Name your signature",
@@ -676,7 +698,9 @@
"WinoUpgradeDescription": "Wino offers 3 accounts to start with for free. If you need more than 3 accounts, please upgrade", "WinoUpgradeDescription": "Wino offers 3 accounts to start with for free. If you need more than 3 accounts, please upgrade",
"WinoUpgradeMessage": "Upgrade to Unlimited Accounts", "WinoUpgradeMessage": "Upgrade to Unlimited Accounts",
"WinoUpgradeRemainingAccountsMessage": "{0} out of {1} free accounts used.", "WinoUpgradeRemainingAccountsMessage": "{0} out of {1} free accounts used.",
"Yesterday": "Yesterday" "Yesterday": "Yesterday",
"SettingsAppPreferences_EmailSyncInterval_Title": "Email sync interval",
"SettingsAppPreferences_EmailSyncInterval_Description": "Automatic email synchronization interval (minutes). This setting will be applied only after restarting Wino Mail."
} }

View File

@@ -4,9 +4,9 @@
"AccountAlias_Column_Verified": "Vérifié", "AccountAlias_Column_Verified": "Vérifié",
"AccountAlias_Disclaimer_FirstLine": "Wino peut uniquement importer des alias pour vos comptes Gmail.", "AccountAlias_Disclaimer_FirstLine": "Wino peut uniquement importer des alias pour vos comptes Gmail.",
"AccountAlias_Disclaimer_SecondLine": "Si vous souhaitez utiliser des alias pour votre compte Outlook ou IMAP, veuillez les ajouter manuellement.", "AccountAlias_Disclaimer_SecondLine": "Si vous souhaitez utiliser des alias pour votre compte Outlook ou IMAP, veuillez les ajouter manuellement.",
"AccountCacheReset_Title": "Account Cache Reset", "AccountCacheReset_Title": "Réinitialiser le cache du compte",
"AccountCacheReset_Message": "This account requires full re-sychronization to continue working. Please wait while Wino re-synchronizes your messages...", "AccountCacheReset_Message": "Ce compte nécessite une resynchronisation complète pour continuer à fonctionner. Veuillez patienter pendant que Wino synchronise à nouveau vos messages...",
"AccountContactNameYou": "You", "AccountContactNameYou": "Vous",
"AccountCreationDialog_Completed": "tout est prêt", "AccountCreationDialog_Completed": "tout est prêt",
"AccountCreationDialog_FetchingEvents": "Récupération des événements de l'agenda.", "AccountCreationDialog_FetchingEvents": "Récupération des événements de l'agenda.",
"AccountCreationDialog_FetchingProfileInformation": "Récupération des détails du profil.", "AccountCreationDialog_FetchingProfileInformation": "Récupération des détails du profil.",
@@ -22,6 +22,10 @@
"AccountPickerDialog_Title": "Choisir un compte", "AccountPickerDialog_Title": "Choisir un compte",
"AccountSettingsDialog_AccountName": "Nom d'affichage de l'expéditeur", "AccountSettingsDialog_AccountName": "Nom d'affichage de l'expéditeur",
"AccountSettingsDialog_AccountNamePlaceholder": "ex. Jean Dupont", "AccountSettingsDialog_AccountNamePlaceholder": "ex. Jean Dupont",
"AccountDetailsPage_Title": "Détails du compte",
"AccountDetailsPage_Description": "Modifiez le nom du compte dans Wino et définissez le nom de l'expéditeur désiré.",
"AccountDetailsPage_ColorPicker_Title": "Couleur du compte",
"AccountDetailsPage_ColorPicker_Description": "Attribuez une nouvelle couleur de compte pour coloriser son symbole dans la liste.",
"AddHyperlink": "Ajouter", "AddHyperlink": "Ajouter",
"AppCloseBackgroundSynchronizationWarningTitle": "Synchronisation en arrière-plan", "AppCloseBackgroundSynchronizationWarningTitle": "Synchronisation en arrière-plan",
"AppCloseStartupLaunchDisabledWarningMessageFirstLine": "L'application n'a pas été configurée pour être lancée au démarrage de Windows.", "AppCloseStartupLaunchDisabledWarningMessageFirstLine": "L'application n'a pas été configurée pour être lancée au démarrage de Windows.",
@@ -77,7 +81,7 @@
"CalendarDisplayOptions_Expand": "Agrandir", "CalendarDisplayOptions_Expand": "Agrandir",
"CalendarItem_DetailsPopup_JoinOnline": "Rejoindre en ligne", "CalendarItem_DetailsPopup_JoinOnline": "Rejoindre en ligne",
"CalendarItem_DetailsPopup_ViewEventButton": "Afficher l'événement", "CalendarItem_DetailsPopup_ViewEventButton": "Afficher l'événement",
"CalendarItem_DetailsPopup_ViewSeriesButton": "View series", "CalendarItem_DetailsPopup_ViewSeriesButton": "Afficher les séries",
"CalendarItemAllDay": "toute la journée", "CalendarItemAllDay": "toute la journée",
"CategoriesFolderNameOverride": "Catégories", "CategoriesFolderNameOverride": "Catégories",
"Center": "Centrer", "Center": "Centrer",
@@ -184,7 +188,7 @@
"Exception_ImapClientPoolFailed": "Échec du groupement de clients IMAP.", "Exception_ImapClientPoolFailed": "Échec du groupement de clients IMAP.",
"Exception_InboxNotAvailable": "Impossible de configurer les dossiers du compte.", "Exception_InboxNotAvailable": "Impossible de configurer les dossiers du compte.",
"Exception_InvalidSystemFolderConfiguration": "La configuration du dossier système nest pas valide. Vérifiez la configuration et réessayez.", "Exception_InvalidSystemFolderConfiguration": "La configuration du dossier système nest pas valide. Vérifiez la configuration et réessayez.",
"Exception_InvalidMultiAccountMoveTarget": "You can't move multiple items that belong to different accounts in linked account.", "Exception_InvalidMultiAccountMoveTarget": "Vous ne pouvez pas déplacer plusieurs éléments qui appartiennent à différents comptes dans le compte lié.",
"Exception_MailProcessing": "Ce message est encore en cours de traitement. Veuillez réessayer dans quelques secondes.", "Exception_MailProcessing": "Ce message est encore en cours de traitement. Veuillez réessayer dans quelques secondes.",
"Exception_MissingAlias": "L'alias principal n'existe pas pour ce compte. La création du brouillon a échoué.", "Exception_MissingAlias": "L'alias principal n'existe pas pour ce compte. La création du brouillon a échoué.",
"Exception_NullAssignedAccount": "Le compte assigné est null", "Exception_NullAssignedAccount": "Le compte assigné est null",
@@ -217,9 +221,9 @@
"GeneralTitle_Error": "Erreur", "GeneralTitle_Error": "Erreur",
"GeneralTitle_Info": "Information", "GeneralTitle_Info": "Information",
"GeneralTitle_Warning": "Avertissement", "GeneralTitle_Warning": "Avertissement",
"GmailServiceDisabled_Title": "Gmail Error", "GmailServiceDisabled_Title": "Erreur Gmail",
"GmailServiceDisabled_Message": "Your Google Workspace account seems to be disabled for Gmail service. Please contact your administrator to enable Gmail service for your account.", "GmailServiceDisabled_Message": "Votre compte Google Workspace semble être désactivé pour le service Gmail. Veuillez contacter votre administrateur pour activer le service Gmail pour votre compte.",
"GmailArchiveFolderNameOverride": "Archive", "GmailArchiveFolderNameOverride": "Archives",
"HoverActionOption_Archive": "Archiver", "HoverActionOption_Archive": "Archiver",
"HoverActionOption_Delete": "Supprimer", "HoverActionOption_Delete": "Supprimer",
"HoverActionOption_MoveJunk": "Déplacer vers courriers indésirables", "HoverActionOption_MoveJunk": "Déplacer vers courriers indésirables",
@@ -228,22 +232,22 @@
"ImageRenderingDisabled": "L'affichage d'image est désactivé pour ce message.", "ImageRenderingDisabled": "L'affichage d'image est désactivé pour ce message.",
"ImapAdvancedSetupDialog_AuthenticationMethod": "Méthode dauthentification", "ImapAdvancedSetupDialog_AuthenticationMethod": "Méthode dauthentification",
"ImapAdvancedSetupDialog_ConnectionSecurity": "Sécurité de la connexion", "ImapAdvancedSetupDialog_ConnectionSecurity": "Sécurité de la connexion",
"IMAPAdvancedSetupDialog_ValidationAuthMethodRequired": "Authentication method is required", "IMAPAdvancedSetupDialog_ValidationAuthMethodRequired": "La méthode d'authentification est requise",
"IMAPAdvancedSetupDialog_ValidationConnectionSecurityRequired": "Connection security type is required", "IMAPAdvancedSetupDialog_ValidationConnectionSecurityRequired": "Le type de sécurité de connexion est requis",
"IMAPAdvancedSetupDialog_ValidationDisplayNameRequired": "Display name is required", "IMAPAdvancedSetupDialog_ValidationDisplayNameRequired": "Le nom affiché est requis",
"IMAPAdvancedSetupDialog_ValidationEmailInvalid": "Please enter a valid email address", "IMAPAdvancedSetupDialog_ValidationEmailInvalid": "Veuillez entrer une adresse e-mail valide",
"IMAPAdvancedSetupDialog_ValidationEmailRequired": "Email address is required", "IMAPAdvancedSetupDialog_ValidationEmailRequired": "Une adresse e-mail est requise",
"IMAPAdvancedSetupDialog_ValidationErrorTitle": "Please check the following:", "IMAPAdvancedSetupDialog_ValidationErrorTitle": "Veuillez vérifier les éléments suivants :",
"IMAPAdvancedSetupDialog_ValidationIncomingPortInvalid": "Incoming port must be between 1-65535", "IMAPAdvancedSetupDialog_ValidationIncomingPortInvalid": "Le port entrant doit être compris entre 1 et 65535",
"IMAPAdvancedSetupDialog_ValidationIncomingPortRequired": "Incoming server port is required", "IMAPAdvancedSetupDialog_ValidationIncomingPortRequired": "Le port du serveur entrant est requis",
"IMAPAdvancedSetupDialog_ValidationIncomingServerRequired": "Incoming server address is required", "IMAPAdvancedSetupDialog_ValidationIncomingServerRequired": "L'adresse du serveur entrant est requise",
"IMAPAdvancedSetupDialog_ValidationOutgoingPasswordRequired": "Outgoing server password is required", "IMAPAdvancedSetupDialog_ValidationOutgoingPasswordRequired": "Le mot de passe du serveur sortant est requis",
"IMAPAdvancedSetupDialog_ValidationOutgoingPortInvalid": "Outgoing port must be between 1-65535", "IMAPAdvancedSetupDialog_ValidationOutgoingPortInvalid": "Le port sortant doit être compris entre 1 et 65535",
"IMAPAdvancedSetupDialog_ValidationOutgoingPortRequired": "Outgoing server port is required", "IMAPAdvancedSetupDialog_ValidationOutgoingPortRequired": "Le port du serveur sortant est requis",
"IMAPAdvancedSetupDialog_ValidationOutgoingServerRequired": "Outgoing server address is required", "IMAPAdvancedSetupDialog_ValidationOutgoingServerRequired": "L'adresse du serveur sortant est requise",
"IMAPAdvancedSetupDialog_ValidationOutgoingUsernameRequired": "Outgoing server username is required", "IMAPAdvancedSetupDialog_ValidationOutgoingUsernameRequired": "Le nom d'utilisateur du serveur sortant est requis",
"IMAPAdvancedSetupDialog_ValidationPasswordRequired": "Password is required", "IMAPAdvancedSetupDialog_ValidationPasswordRequired": "Le mot de passe est requis",
"IMAPAdvancedSetupDialog_ValidationUsernameRequired": "Username is required", "IMAPAdvancedSetupDialog_ValidationUsernameRequired": "Le nom d'utilisateur est requis",
"ImapAuthenticationMethod_Auto": "Automatique", "ImapAuthenticationMethod_Auto": "Automatique",
"ImapAuthenticationMethod_CramMD5": "CRAM-MD5", "ImapAuthenticationMethod_CramMD5": "CRAM-MD5",
"ImapAuthenticationMethod_DigestMD5": "DIGEST-MD5", "ImapAuthenticationMethod_DigestMD5": "DIGEST-MD5",
@@ -256,6 +260,11 @@
"ImapConnectionSecurity_SslTls": "SSL/TLS", "ImapConnectionSecurity_SslTls": "SSL/TLS",
"ImapConnectionSecurity_StartTls": "STARTTLS", "ImapConnectionSecurity_StartTls": "STARTTLS",
"IMAPSetupDialog_AccountType": "Type de compte", "IMAPSetupDialog_AccountType": "Type de compte",
"IMAPSetupDialog_ValidationSuccess_Title": "Opération réussie",
"IMAPSetupDialog_ValidationSuccess_Message": "Validation réussie",
"IMAPSetupDialog_SaveImapSuccess_Title": "Success",
"IMAPSetupDialog_SaveImapSuccess_Message": "IMAP settings saved successfuly.",
"IMAPSetupDialog_ValidationFailed_Title": "Échec de la validation du serveur IMAP.",
"IMAPSetupDialog_CertificateAllowanceRequired_Row0": "Ce serveur demande une liaison SSL pour continuer. Veuillez confirmer les détails du certificat ci-dessous.", "IMAPSetupDialog_CertificateAllowanceRequired_Row0": "Ce serveur demande une liaison SSL pour continuer. Veuillez confirmer les détails du certificat ci-dessous.",
"IMAPSetupDialog_CertificateAllowanceRequired_Row1": "Autorisez la négociation SSL à continuer à configurer votre compte.", "IMAPSetupDialog_CertificateAllowanceRequired_Row1": "Autorisez la négociation SSL à continuer à configurer votre compte.",
"IMAPSetupDialog_CertificateDenied": "L'utilisateur n'a pas autorisé la négociation avec le certificat.", "IMAPSetupDialog_CertificateDenied": "L'utilisateur n'a pas autorisé la négociation avec le certificat.",
@@ -270,6 +279,8 @@
"IMAPSetupDialog_DisplayNamePlaceholder": "ex. Jean Dupont", "IMAPSetupDialog_DisplayNamePlaceholder": "ex. Jean Dupont",
"IMAPSetupDialog_IncomingMailServer": "Serveur de courrier entrant", "IMAPSetupDialog_IncomingMailServer": "Serveur de courrier entrant",
"IMAPSetupDialog_IncomingMailServerPort": "Port", "IMAPSetupDialog_IncomingMailServerPort": "Port",
"IMAPSetupDialog_IMAPSettings": "Paramètres du serveur IMAP",
"IMAPSetupDialog_SMTPSettings": "Paramètres du serveur SMTP",
"IMAPSetupDialog_MailAddress": "Adresse e-mail", "IMAPSetupDialog_MailAddress": "Adresse e-mail",
"IMAPSetupDialog_MailAddressPlaceholder": "personne@example.com", "IMAPSetupDialog_MailAddressPlaceholder": "personne@example.com",
"IMAPSetupDialog_OutgoingMailServer": "Serveur de courrier sortant (SMTP)", "IMAPSetupDialog_OutgoingMailServer": "Serveur de courrier sortant (SMTP)",
@@ -310,7 +321,7 @@
"Info_DraftFolderMissingMessage": "Le dossier Brouillon est manquant pour ce compte. Veuillez vérifier vos paramètres de compte.", "Info_DraftFolderMissingMessage": "Le dossier Brouillon est manquant pour ce compte. Veuillez vérifier vos paramètres de compte.",
"Info_DraftFolderMissingTitle": "Dossier brouillon manquant", "Info_DraftFolderMissingTitle": "Dossier brouillon manquant",
"Info_FailedToOpenFileMessage": "Le fichier a peut-être été supprimé du disque dur.", "Info_FailedToOpenFileMessage": "Le fichier a peut-être été supprimé du disque dur.",
"Info_FailedToOpenFileTitle": "Failed to launch file.", "Info_FailedToOpenFileTitle": "Échec du lancement du fichier.",
"Info_FileLaunchFailedTitle": "Échec du lancement du fichier", "Info_FileLaunchFailedTitle": "Échec du lancement du fichier",
"Info_InvalidAddressMessage": "{0} n'est pas une adresse e-mail valide.", "Info_InvalidAddressMessage": "{0} n'est pas une adresse e-mail valide.",
"Info_InvalidAddressTitle": "Addresse invalide", "Info_InvalidAddressTitle": "Addresse invalide",
@@ -423,9 +434,9 @@
"Notifications_MultipleNotificationsTitle": "Nouveau message", "Notifications_MultipleNotificationsTitle": "Nouveau message",
"Notifications_WinoUpdatedMessage": "Vérifier la nouvelle version {0}", "Notifications_WinoUpdatedMessage": "Vérifier la nouvelle version {0}",
"Notifications_WinoUpdatedTitle": "Wino Mail a été mis à jour.", "Notifications_WinoUpdatedTitle": "Wino Mail a été mis à jour.",
"OnlineSearchFailed_Message": "Failed to perform search\n{0}\n\nListing offline mails.", "OnlineSearchFailed_Message": "Impossible d'effectuer la recherche\n{0}\n\nListe des e-mails hors ligne.",
"OnlineSearchTry_Line1": "Can't find what you are looking for?", "OnlineSearchTry_Line1": "Vous ne trouvez pas ce que vous cherchez ?",
"OnlineSearchTry_Line2": "Try online search.", "OnlineSearchTry_Line2": "Essayez une recherche en ligne.",
"Other": "Autres", "Other": "Autres",
"PaneLengthOption_Default": "Défaut", "PaneLengthOption_Default": "Défaut",
"PaneLengthOption_ExtraLarge": "Très grand", "PaneLengthOption_ExtraLarge": "Très grand",
@@ -437,11 +448,11 @@
"PreparingFoldersMessage": "Préparation des dossiers", "PreparingFoldersMessage": "Préparation des dossiers",
"ProtocolLogAvailable_Message": "Les journaux de protocole sont disponibles pour les diagnostics.", "ProtocolLogAvailable_Message": "Les journaux de protocole sont disponibles pour les diagnostics.",
"ProviderDetail_Gmail_Description": "Compte Google", "ProviderDetail_Gmail_Description": "Compte Google",
"ProviderDetail_iCloud_Description": "Apple iCloud Account", "ProviderDetail_iCloud_Description": "Compte iCloud d'Apple",
"ProviderDetail_iCloud_Title": "iCloud", "ProviderDetail_iCloud_Title": "iCloud",
"ProviderDetail_IMAP_Description": "Serveur IMAP/SMTP personnalisé", "ProviderDetail_IMAP_Description": "Serveur IMAP/SMTP personnalisé",
"ProviderDetail_IMAP_Title": "Serveur IMAP", "ProviderDetail_IMAP_Title": "Serveur IMAP",
"ProviderDetail_Yahoo_Description": "Yahoo Account", "ProviderDetail_Yahoo_Description": "Compte Yahoo",
"ProviderDetail_Yahoo_Title": "Yahoo Mail", "ProviderDetail_Yahoo_Title": "Yahoo Mail",
"QuickEventDialog_EventName": "Titre de l'événement", "QuickEventDialog_EventName": "Titre de l'événement",
"QuickEventDialog_IsAllDay": "Toute la journée", "QuickEventDialog_IsAllDay": "Toute la journée",
@@ -455,6 +466,8 @@
"SearchingIn": "Recherche dans", "SearchingIn": "Recherche dans",
"SearchPivotName": "Résultats", "SearchPivotName": "Résultats",
"SettingConfigureSpecialFolders_Button": "Configurer", "SettingConfigureSpecialFolders_Button": "Configurer",
"SettingsEditAccountDetails_IMAPConfiguration_Title": "Configuration IMAP/SMTP",
"SettingsEditAccountDetails_IMAPConfiguration_Description": "Modifiez vos paramètres de serveur entrant/sortant.",
"SettingsAbout_Description": "En savoir plus sur Wino.", "SettingsAbout_Description": "En savoir plus sur Wino.",
"SettingsAbout_Title": "À propos", "SettingsAbout_Title": "À propos",
"SettingsAboutGithub_Description": "Ouvrir le gestionnaire de tickets du dépôt GitHub.", "SettingsAboutGithub_Description": "Ouvrir le gestionnaire de tickets du dépôt GitHub.",
@@ -473,10 +486,10 @@
"SettingsAppPreferences_CloseBehavior_Description": "Que se passe-t-il lorsque vous fermez l'application?", "SettingsAppPreferences_CloseBehavior_Description": "Que se passe-t-il lorsque vous fermez l'application?",
"SettingsAppPreferences_CloseBehavior_Title": "Comportement de fermeture de l'application", "SettingsAppPreferences_CloseBehavior_Title": "Comportement de fermeture de l'application",
"SettingsAppPreferences_Description": "Paramètres généraux / préférences pour Wino Mail.", "SettingsAppPreferences_Description": "Paramètres généraux / préférences pour Wino Mail.",
"SettingsAppPreferences_SearchMode_Description": "Set whether Wino should check fetched mails first while doing a search or ask your mail server online. Local search is always faster and you can always do an online search if your mail is not in the results.", "SettingsAppPreferences_SearchMode_Description": "Définissez si Wino doit d'abord vérifier les messages récupérés lors d'une recherche ou demandez à votre serveur de messagerie en ligne. La recherche locale est toujours plus rapide et vous pouvez toujours effectuer une recherche en ligne si votre courrier n'est pas dans les résultats.",
"SettingsAppPreferences_SearchMode_Local": "Local", "SettingsAppPreferences_SearchMode_Local": "Local",
"SettingsAppPreferences_SearchMode_Online": "Online", "SettingsAppPreferences_SearchMode_Online": "En ligne",
"SettingsAppPreferences_SearchMode_Title": "Default search mode", "SettingsAppPreferences_SearchMode_Title": "Mode de recherche par défaut",
"SettingsAppPreferences_ServerBackgroundingMode_Invisible_Description": "Wino Mail continuera à fonctionner en arrière-plan. Vous serez informé de l'arrivée de nouveaux courriers.", "SettingsAppPreferences_ServerBackgroundingMode_Invisible_Description": "Wino Mail continuera à fonctionner en arrière-plan. Vous serez informé de l'arrivée de nouveaux courriers.",
"SettingsAppPreferences_ServerBackgroundingMode_Invisible_Title": "Exécuter en arrière-plan", "SettingsAppPreferences_ServerBackgroundingMode_Invisible_Title": "Exécuter en arrière-plan",
"SettingsAppPreferences_ServerBackgroundingMode_MinimizeTray_Description": "Wino Mail fonctionne en permanence dans la barre d'état système. Il est possible de le lancer en cliquant sur une icône. Vous serez informé de l'arrivée de nouveaux messages.", "SettingsAppPreferences_ServerBackgroundingMode_MinimizeTray_Description": "Wino Mail fonctionne en permanence dans la barre d'état système. Il est possible de le lancer en cliquant sur une icône. Vous serez informé de l'arrivée de nouveaux messages.",
@@ -508,11 +521,11 @@
"SettingsCustomTheme_Title": "Thème personnalisé", "SettingsCustomTheme_Title": "Thème personnalisé",
"SettingsDeleteAccount_Description": "Supprimer tous les e-mails et identifiants associés à ce compte.", "SettingsDeleteAccount_Description": "Supprimer tous les e-mails et identifiants associés à ce compte.",
"SettingsDeleteAccount_Title": "Supprimer ce compte", "SettingsDeleteAccount_Title": "Supprimer ce compte",
"SettingsDeleteProtection_Description": "Wino devrait-il vous demander une confirmation chaque fois que vous essayez de supprimer définitivement un mail en utilisant les touches Maj + Suppr ?", "SettingsDeleteProtection_Description": "Should Wino ask you for confirmation every time you try to permanently delete a mail using Shift + Del keys?",
"SettingsDeleteProtection_Title": "Protection contre la suppression permanente", "SettingsDeleteProtection_Title": "Protection contre la suppression permanente",
"SettingsDiagnostics_Description": "Pour les développeurs", "SettingsDiagnostics_Description": "Pour les développeurs",
"SettingsDiagnostics_DiagnosticId_Description": "Share this ID with the developers when asked to get help for the issues you experience in Wino Mail.", "SettingsDiagnostics_DiagnosticId_Description": "Partagez cet identifiant avec les développeurs lorsqu'ils vous aideront à résoudre les problèmes que vous rencontrez dans Wino Mail.",
"SettingsDiagnostics_DiagnosticId_Title": "Diagnostic ID", "SettingsDiagnostics_DiagnosticId_Title": "ID de diagnostic",
"SettingsDiagnostics_Title": "Diagnostics", "SettingsDiagnostics_Title": "Diagnostics",
"SettingsDiscord_Description": "Obtenez des mises à jour régulières sur le développement, participez aux discussions sur la feuille de route et donnez votre avis.", "SettingsDiscord_Description": "Obtenez des mises à jour régulières sur le développement, participez aux discussions sur la feuille de route et donnez votre avis.",
"SettingsDiscord_Title": "Canal Discord", "SettingsDiscord_Title": "Canal Discord",
@@ -566,6 +579,8 @@
"SettingsManageAccountSettings_Title": "Gérer les paramètres du compte", "SettingsManageAccountSettings_Title": "Gérer les paramètres du compte",
"SettingsManageAliases_Description": "Voir les alias de messagerie assignés à ce compte, les mettre à jour ou les supprimer.", "SettingsManageAliases_Description": "Voir les alias de messagerie assignés à ce compte, les mettre à jour ou les supprimer.",
"SettingsManageAliases_Title": "Alias", "SettingsManageAliases_Title": "Alias",
"SettingsEditAccountDetails_Title": "Modifier les détails du compte",
"SettingsEditAccountDetails_Description": "Changez le nom du compte, le nom de l'expéditeur et attribuez une nouvelle couleur si vous le souhaitez.",
"SettingsManageLink_Description": "Déplacer des éléments pour ajouter un nouveau lien ou supprimer un lien existant.", "SettingsManageLink_Description": "Déplacer des éléments pour ajouter un nouveau lien ou supprimer un lien existant.",
"SettingsManageLink_Title": "Gérer le lien", "SettingsManageLink_Title": "Gérer le lien",
"SettingsMarkAsRead_Description": "Modifier ce qui doit arriver à l'élément sélectionné.", "SettingsMarkAsRead_Description": "Modifier ce qui doit arriver à l'élément sélectionné.",
@@ -610,6 +625,11 @@
"SettingsShowPreviewText_Title": "Afficher l'aperçu du texte", "SettingsShowPreviewText_Title": "Afficher l'aperçu du texte",
"SettingsShowSenderPictures_Description": "Masquer/afficher les vignettes des images de l'expéditeur.", "SettingsShowSenderPictures_Description": "Masquer/afficher les vignettes des images de l'expéditeur.",
"SettingsShowSenderPictures_Title": "Afficher l'avatar de l'expéditeur", "SettingsShowSenderPictures_Title": "Afficher l'avatar de l'expéditeur",
"SettingsEnableGravatarAvatars_Title": "Gravatar",
"SettingsEnableGravatarAvatars_Description": "Use gravatar (if available) as sender picture",
"SettingsEnableFavicons_Title": "Domain icons (Favicons)",
"SettingsEnableFavicons_Description": "Use domain favicons (if available) as sender picture",
"SettingsMailList_ClearAvatarsCache_Button": "Clear cached avatars",
"SettingsSignature_AddCustomSignature_Button": "Ajouter une signature", "SettingsSignature_AddCustomSignature_Button": "Ajouter une signature",
"SettingsSignature_AddCustomSignature_Title": "Ajouter une signature personnalisée", "SettingsSignature_AddCustomSignature_Title": "Ajouter une signature personnalisée",
"SettingsSignature_DeleteSignature_Title": "Supprimer la signature", "SettingsSignature_DeleteSignature_Title": "Supprimer la signature",
@@ -631,6 +651,8 @@
"SettingsThreads_Title": "Affichage en mode conversation", "SettingsThreads_Title": "Affichage en mode conversation",
"SettingsUnlinkAccounts_Description": "Supprimer le lien entre les comptes. Cela ne supprimera pas vos comptes.", "SettingsUnlinkAccounts_Description": "Supprimer le lien entre les comptes. Cela ne supprimera pas vos comptes.",
"SettingsUnlinkAccounts_Title": "Dissocier les comptes", "SettingsUnlinkAccounts_Title": "Dissocier les comptes",
"SettingsMailRendering_ActionLabels_Title": "Action labels",
"SettingsMailRendering_ActionLabels_Description": "Show action labels.",
"SignatureDeleteDialog_Message": "Êtes-vous sûr de vouloir supprimer la signature « {0} » ?", "SignatureDeleteDialog_Message": "Êtes-vous sûr de vouloir supprimer la signature « {0} » ?",
"SignatureDeleteDialog_Title": "Supprimer la signature", "SignatureDeleteDialog_Title": "Supprimer la signature",
"SignatureEditorDialog_SignatureName_Placeholder": "Nom de la signature", "SignatureEditorDialog_SignatureName_Placeholder": "Nom de la signature",
@@ -676,7 +698,9 @@
"WinoUpgradeDescription": "Wino offre 3 comptes gratuits pour commencer. Si vous avez besoin de plus de 3 comptes, veuillez passer à la version supérieure", "WinoUpgradeDescription": "Wino offre 3 comptes gratuits pour commencer. Si vous avez besoin de plus de 3 comptes, veuillez passer à la version supérieure",
"WinoUpgradeMessage": "Mettre à niveau vers des comptes illimités", "WinoUpgradeMessage": "Mettre à niveau vers des comptes illimités",
"WinoUpgradeRemainingAccountsMessage": "{0} comptes gratuits utilisés sur {1}.", "WinoUpgradeRemainingAccountsMessage": "{0} comptes gratuits utilisés sur {1}.",
"Yesterday": "Hier" "Yesterday": "Hier",
"SettingsAppPreferences_EmailSyncInterval_Title": "Email sync interval",
"SettingsAppPreferences_EmailSyncInterval_Description": "Automatic email synchronization interval (minutes). This setting will be applied only after restarting Wino Mail."
} }

View File

@@ -22,6 +22,10 @@
"AccountPickerDialog_Title": "Escolla unha conta", "AccountPickerDialog_Title": "Escolla unha conta",
"AccountSettingsDialog_AccountName": "Nome do remitente", "AccountSettingsDialog_AccountName": "Nome do remitente",
"AccountSettingsDialog_AccountNamePlaceholder": "p.ex. Manuel Rivas", "AccountSettingsDialog_AccountNamePlaceholder": "p.ex. Manuel Rivas",
"AccountDetailsPage_Title": "Account info",
"AccountDetailsPage_Description": "Change the name of the account in Wino and set desired sender name.",
"AccountDetailsPage_ColorPicker_Title": "Account color",
"AccountDetailsPage_ColorPicker_Description": "Assign a new account color to colorize its symbol in the list.",
"AddHyperlink": "Engadir", "AddHyperlink": "Engadir",
"AppCloseBackgroundSynchronizationWarningTitle": "Sincronización en segundo plano", "AppCloseBackgroundSynchronizationWarningTitle": "Sincronización en segundo plano",
"AppCloseStartupLaunchDisabledWarningMessageFirstLine": "Application has not been set to launch on Windows startup.", "AppCloseStartupLaunchDisabledWarningMessageFirstLine": "Application has not been set to launch on Windows startup.",
@@ -256,6 +260,11 @@
"ImapConnectionSecurity_SslTls": "SSL/TLS", "ImapConnectionSecurity_SslTls": "SSL/TLS",
"ImapConnectionSecurity_StartTls": "STARTTLS", "ImapConnectionSecurity_StartTls": "STARTTLS",
"IMAPSetupDialog_AccountType": "Tipo de conta", "IMAPSetupDialog_AccountType": "Tipo de conta",
"IMAPSetupDialog_ValidationSuccess_Title": "Success",
"IMAPSetupDialog_ValidationSuccess_Message": "Validation successful",
"IMAPSetupDialog_SaveImapSuccess_Title": "Success",
"IMAPSetupDialog_SaveImapSuccess_Message": "IMAP settings saved successfuly.",
"IMAPSetupDialog_ValidationFailed_Title": "IMAP Server validation failed.",
"IMAPSetupDialog_CertificateAllowanceRequired_Row0": "This server is requesting a SSL handshake to continue. Please confirm the certificate details below.", "IMAPSetupDialog_CertificateAllowanceRequired_Row0": "This server is requesting a SSL handshake to continue. Please confirm the certificate details below.",
"IMAPSetupDialog_CertificateAllowanceRequired_Row1": "Allow the handshake to continue setting up your account.", "IMAPSetupDialog_CertificateAllowanceRequired_Row1": "Allow the handshake to continue setting up your account.",
"IMAPSetupDialog_CertificateDenied": "User didn't authorize the handshake with the certificate.", "IMAPSetupDialog_CertificateDenied": "User didn't authorize the handshake with the certificate.",
@@ -270,6 +279,8 @@
"IMAPSetupDialog_DisplayNamePlaceholder": "p.ex. Manuel Rivas", "IMAPSetupDialog_DisplayNamePlaceholder": "p.ex. Manuel Rivas",
"IMAPSetupDialog_IncomingMailServer": "Servidor de correo entrante", "IMAPSetupDialog_IncomingMailServer": "Servidor de correo entrante",
"IMAPSetupDialog_IncomingMailServerPort": "Porto", "IMAPSetupDialog_IncomingMailServerPort": "Porto",
"IMAPSetupDialog_IMAPSettings": "IMAP Server Settings",
"IMAPSetupDialog_SMTPSettings": "SMTP Server Settings",
"IMAPSetupDialog_MailAddress": "Enderezo de correo electrónico", "IMAPSetupDialog_MailAddress": "Enderezo de correo electrónico",
"IMAPSetupDialog_MailAddressPlaceholder": "nome@exemplo.gal", "IMAPSetupDialog_MailAddressPlaceholder": "nome@exemplo.gal",
"IMAPSetupDialog_OutgoingMailServer": "Servidor de saída (SMPT)", "IMAPSetupDialog_OutgoingMailServer": "Servidor de saída (SMPT)",
@@ -455,6 +466,8 @@
"SearchingIn": "Searching in", "SearchingIn": "Searching in",
"SearchPivotName": "Results", "SearchPivotName": "Results",
"SettingConfigureSpecialFolders_Button": "Configure", "SettingConfigureSpecialFolders_Button": "Configure",
"SettingsEditAccountDetails_IMAPConfiguration_Title": "IMAP/SMTP Configuration",
"SettingsEditAccountDetails_IMAPConfiguration_Description": "Change your incoming/outgoing server settings.",
"SettingsAbout_Description": "Learn more about Wino.", "SettingsAbout_Description": "Learn more about Wino.",
"SettingsAbout_Title": "About", "SettingsAbout_Title": "About",
"SettingsAboutGithub_Description": "Go to issue tracker GitHub repository.", "SettingsAboutGithub_Description": "Go to issue tracker GitHub repository.",
@@ -508,7 +521,7 @@
"SettingsCustomTheme_Title": "Custom Theme", "SettingsCustomTheme_Title": "Custom Theme",
"SettingsDeleteAccount_Description": "Delete all e-mails and credentials associated with this account.", "SettingsDeleteAccount_Description": "Delete all e-mails and credentials associated with this account.",
"SettingsDeleteAccount_Title": "Delete this account", "SettingsDeleteAccount_Title": "Delete this account",
"SettingsDeleteProtection_Description": "Should Wino ask you for comfirmation every time you try to permanently delete a mail using Shift + Del keys?", "SettingsDeleteProtection_Description": "Should Wino ask you for confirmation every time you try to permanently delete a mail using Shift + Del keys?",
"SettingsDeleteProtection_Title": "Permanent Delete Protection", "SettingsDeleteProtection_Title": "Permanent Delete Protection",
"SettingsDiagnostics_Description": "For developers", "SettingsDiagnostics_Description": "For developers",
"SettingsDiagnostics_DiagnosticId_Description": "Share this ID with the developers when asked to get help for the issues you experience in Wino Mail.", "SettingsDiagnostics_DiagnosticId_Description": "Share this ID with the developers when asked to get help for the issues you experience in Wino Mail.",
@@ -566,6 +579,8 @@
"SettingsManageAccountSettings_Title": "Manage Account Settings", "SettingsManageAccountSettings_Title": "Manage Account Settings",
"SettingsManageAliases_Description": "See e-mail aliases assigned for this account, update or delete them.", "SettingsManageAliases_Description": "See e-mail aliases assigned for this account, update or delete them.",
"SettingsManageAliases_Title": "Aliases", "SettingsManageAliases_Title": "Aliases",
"SettingsEditAccountDetails_Title": "Edit Account Details",
"SettingsEditAccountDetails_Description": "Change account name, sender name and assign a new color if you like.",
"SettingsManageLink_Description": "Move items to add new link or remove existing link.", "SettingsManageLink_Description": "Move items to add new link or remove existing link.",
"SettingsManageLink_Title": "Manage Link", "SettingsManageLink_Title": "Manage Link",
"SettingsMarkAsRead_Description": "Change what should happen to the selected item.", "SettingsMarkAsRead_Description": "Change what should happen to the selected item.",
@@ -610,6 +625,11 @@
"SettingsShowPreviewText_Title": "Show Preview Text", "SettingsShowPreviewText_Title": "Show Preview Text",
"SettingsShowSenderPictures_Description": "Hide/show the thumbnail sender pictures.", "SettingsShowSenderPictures_Description": "Hide/show the thumbnail sender pictures.",
"SettingsShowSenderPictures_Title": "Show Sender Avatars", "SettingsShowSenderPictures_Title": "Show Sender Avatars",
"SettingsEnableGravatarAvatars_Title": "Gravatar",
"SettingsEnableGravatarAvatars_Description": "Use gravatar (if available) as sender picture",
"SettingsEnableFavicons_Title": "Domain icons (Favicons)",
"SettingsEnableFavicons_Description": "Use domain favicons (if available) as sender picture",
"SettingsMailList_ClearAvatarsCache_Button": "Clear cached avatars",
"SettingsSignature_AddCustomSignature_Button": "Add signature", "SettingsSignature_AddCustomSignature_Button": "Add signature",
"SettingsSignature_AddCustomSignature_Title": "Add custom signature", "SettingsSignature_AddCustomSignature_Title": "Add custom signature",
"SettingsSignature_DeleteSignature_Title": "Delete signature", "SettingsSignature_DeleteSignature_Title": "Delete signature",
@@ -631,6 +651,8 @@
"SettingsThreads_Title": "Conversation Threading", "SettingsThreads_Title": "Conversation Threading",
"SettingsUnlinkAccounts_Description": "Remove the link between accounts. his will not delete your accounts.", "SettingsUnlinkAccounts_Description": "Remove the link between accounts. his will not delete your accounts.",
"SettingsUnlinkAccounts_Title": "Unlink Accounts", "SettingsUnlinkAccounts_Title": "Unlink Accounts",
"SettingsMailRendering_ActionLabels_Title": "Action labels",
"SettingsMailRendering_ActionLabels_Description": "Show action labels.",
"SignatureDeleteDialog_Message": "Are you sure you want to delete \"{0}\" signature?", "SignatureDeleteDialog_Message": "Are you sure you want to delete \"{0}\" signature?",
"SignatureDeleteDialog_Title": "Delete signature", "SignatureDeleteDialog_Title": "Delete signature",
"SignatureEditorDialog_SignatureName_Placeholder": "Name your signature", "SignatureEditorDialog_SignatureName_Placeholder": "Name your signature",
@@ -676,7 +698,9 @@
"WinoUpgradeDescription": "Wino offers 3 accounts to start with for free. If you need more than 3 accounts, please upgrade", "WinoUpgradeDescription": "Wino offers 3 accounts to start with for free. If you need more than 3 accounts, please upgrade",
"WinoUpgradeMessage": "Upgrade to Unlimited Accounts", "WinoUpgradeMessage": "Upgrade to Unlimited Accounts",
"WinoUpgradeRemainingAccountsMessage": "{0} out of {1} free accounts used.", "WinoUpgradeRemainingAccountsMessage": "{0} out of {1} free accounts used.",
"Yesterday": "Yesterday" "Yesterday": "Yesterday",
"SettingsAppPreferences_EmailSyncInterval_Title": "Email sync interval",
"SettingsAppPreferences_EmailSyncInterval_Description": "Automatic email synchronization interval (minutes). This setting will be applied only after restarting Wino Mail."
} }

View File

@@ -22,6 +22,10 @@
"AccountPickerDialog_Title": "Pilih akun", "AccountPickerDialog_Title": "Pilih akun",
"AccountSettingsDialog_AccountName": "Nama Tampilan Pengirim", "AccountSettingsDialog_AccountName": "Nama Tampilan Pengirim",
"AccountSettingsDialog_AccountNamePlaceholder": "misal: Budi Susilo", "AccountSettingsDialog_AccountNamePlaceholder": "misal: Budi Susilo",
"AccountDetailsPage_Title": "Account info",
"AccountDetailsPage_Description": "Change the name of the account in Wino and set desired sender name.",
"AccountDetailsPage_ColorPicker_Title": "Account color",
"AccountDetailsPage_ColorPicker_Description": "Assign a new account color to colorize its symbol in the list.",
"AddHyperlink": "Tambahkan", "AddHyperlink": "Tambahkan",
"AppCloseBackgroundSynchronizationWarningTitle": "Penyelarasan Latar Belakang", "AppCloseBackgroundSynchronizationWarningTitle": "Penyelarasan Latar Belakang",
"AppCloseStartupLaunchDisabledWarningMessageFirstLine": "Aplikasi tidak diatur untuk berjalan saat Windows dimulai.", "AppCloseStartupLaunchDisabledWarningMessageFirstLine": "Aplikasi tidak diatur untuk berjalan saat Windows dimulai.",
@@ -256,6 +260,11 @@
"ImapConnectionSecurity_SslTls": "SSL/TLS", "ImapConnectionSecurity_SslTls": "SSL/TLS",
"ImapConnectionSecurity_StartTls": "STARTTLS", "ImapConnectionSecurity_StartTls": "STARTTLS",
"IMAPSetupDialog_AccountType": "Jenis akun", "IMAPSetupDialog_AccountType": "Jenis akun",
"IMAPSetupDialog_ValidationSuccess_Title": "Success",
"IMAPSetupDialog_ValidationSuccess_Message": "Validation successful",
"IMAPSetupDialog_SaveImapSuccess_Title": "Success",
"IMAPSetupDialog_SaveImapSuccess_Message": "IMAP settings saved successfuly.",
"IMAPSetupDialog_ValidationFailed_Title": "IMAP Server validation failed.",
"IMAPSetupDialog_CertificateAllowanceRequired_Row0": "Peladen ini meminta pertukaran SSL untuk melanjutkan. Mohon pastikan rincian sertifikat di bawah ini.", "IMAPSetupDialog_CertificateAllowanceRequired_Row0": "Peladen ini meminta pertukaran SSL untuk melanjutkan. Mohon pastikan rincian sertifikat di bawah ini.",
"IMAPSetupDialog_CertificateAllowanceRequired_Row1": "Izinkan pertukaran untuk melanjutkan mengatur akun Anda.", "IMAPSetupDialog_CertificateAllowanceRequired_Row1": "Izinkan pertukaran untuk melanjutkan mengatur akun Anda.",
"IMAPSetupDialog_CertificateDenied": "Pengguna tidak mengotorisasi pertukaran sertifikat.", "IMAPSetupDialog_CertificateDenied": "Pengguna tidak mengotorisasi pertukaran sertifikat.",
@@ -270,6 +279,8 @@
"IMAPSetupDialog_DisplayNamePlaceholder": "misal: Budi Susilo", "IMAPSetupDialog_DisplayNamePlaceholder": "misal: Budi Susilo",
"IMAPSetupDialog_IncomingMailServer": "Peladen email masuk", "IMAPSetupDialog_IncomingMailServer": "Peladen email masuk",
"IMAPSetupDialog_IncomingMailServerPort": "Port", "IMAPSetupDialog_IncomingMailServerPort": "Port",
"IMAPSetupDialog_IMAPSettings": "IMAP Server Settings",
"IMAPSetupDialog_SMTPSettings": "SMTP Server Settings",
"IMAPSetupDialog_MailAddress": "Alamat surel", "IMAPSetupDialog_MailAddress": "Alamat surel",
"IMAPSetupDialog_MailAddressPlaceholder": "nama@contoh.com", "IMAPSetupDialog_MailAddressPlaceholder": "nama@contoh.com",
"IMAPSetupDialog_OutgoingMailServer": "Peladen surel keluar (SMTP)", "IMAPSetupDialog_OutgoingMailServer": "Peladen surel keluar (SMTP)",
@@ -455,6 +466,8 @@
"SearchingIn": "Mencari di", "SearchingIn": "Mencari di",
"SearchPivotName": "Hasil", "SearchPivotName": "Hasil",
"SettingConfigureSpecialFolders_Button": "Atur", "SettingConfigureSpecialFolders_Button": "Atur",
"SettingsEditAccountDetails_IMAPConfiguration_Title": "IMAP/SMTP Configuration",
"SettingsEditAccountDetails_IMAPConfiguration_Description": "Change your incoming/outgoing server settings.",
"SettingsAbout_Description": "Lebih lanjut tentang Wino.", "SettingsAbout_Description": "Lebih lanjut tentang Wino.",
"SettingsAbout_Title": "Tentang", "SettingsAbout_Title": "Tentang",
"SettingsAboutGithub_Description": "Pergi ke pelacak masalah di repository GitHub.", "SettingsAboutGithub_Description": "Pergi ke pelacak masalah di repository GitHub.",
@@ -508,7 +521,7 @@
"SettingsCustomTheme_Title": "Tema Khusus", "SettingsCustomTheme_Title": "Tema Khusus",
"SettingsDeleteAccount_Description": "Hapus semua surel dan informasi tentang akun ini.", "SettingsDeleteAccount_Description": "Hapus semua surel dan informasi tentang akun ini.",
"SettingsDeleteAccount_Title": "Hapus akun ini", "SettingsDeleteAccount_Title": "Hapus akun ini",
"SettingsDeleteProtection_Description": "Haruskan Wino meminta persetujuan Anda setiap kali Anda menghapus permanen surel dengan tombol Shift + Del?", "SettingsDeleteProtection_Description": "Should Wino ask you for confirmation every time you try to permanently delete a mail using Shift + Del keys?",
"SettingsDeleteProtection_Title": "Perlindungan Hapus Permanen", "SettingsDeleteProtection_Title": "Perlindungan Hapus Permanen",
"SettingsDiagnostics_Description": "Untuk pengembang", "SettingsDiagnostics_Description": "Untuk pengembang",
"SettingsDiagnostics_DiagnosticId_Description": "Share this ID with the developers when asked to get help for the issues you experience in Wino Mail.", "SettingsDiagnostics_DiagnosticId_Description": "Share this ID with the developers when asked to get help for the issues you experience in Wino Mail.",
@@ -566,6 +579,8 @@
"SettingsManageAccountSettings_Title": "Kelole Pengaturan Akun", "SettingsManageAccountSettings_Title": "Kelole Pengaturan Akun",
"SettingsManageAliases_Description": "Lihat, perbarui, dan hapus alias untuk akun ini.", "SettingsManageAliases_Description": "Lihat, perbarui, dan hapus alias untuk akun ini.",
"SettingsManageAliases_Title": "Alias", "SettingsManageAliases_Title": "Alias",
"SettingsEditAccountDetails_Title": "Edit Account Details",
"SettingsEditAccountDetails_Description": "Change account name, sender name and assign a new color if you like.",
"SettingsManageLink_Description": "Pindahkan item untuk menambahkan tautan baru atau hapus tautan yang sudah ada.", "SettingsManageLink_Description": "Pindahkan item untuk menambahkan tautan baru atau hapus tautan yang sudah ada.",
"SettingsManageLink_Title": "Kelola Tautan", "SettingsManageLink_Title": "Kelola Tautan",
"SettingsMarkAsRead_Description": "Ubah apa yang terjadi ke item yang dipilih.", "SettingsMarkAsRead_Description": "Ubah apa yang terjadi ke item yang dipilih.",
@@ -610,6 +625,11 @@
"SettingsShowPreviewText_Title": "Tampilkan Teks Pratinjau", "SettingsShowPreviewText_Title": "Tampilkan Teks Pratinjau",
"SettingsShowSenderPictures_Description": "Sembunyikan/tampilkan foto pengirim.", "SettingsShowSenderPictures_Description": "Sembunyikan/tampilkan foto pengirim.",
"SettingsShowSenderPictures_Title": "Tampilkan Foto Pengirim", "SettingsShowSenderPictures_Title": "Tampilkan Foto Pengirim",
"SettingsEnableGravatarAvatars_Title": "Gravatar",
"SettingsEnableGravatarAvatars_Description": "Use gravatar (if available) as sender picture",
"SettingsEnableFavicons_Title": "Domain icons (Favicons)",
"SettingsEnableFavicons_Description": "Use domain favicons (if available) as sender picture",
"SettingsMailList_ClearAvatarsCache_Button": "Clear cached avatars",
"SettingsSignature_AddCustomSignature_Button": "Tambah tanda tangan", "SettingsSignature_AddCustomSignature_Button": "Tambah tanda tangan",
"SettingsSignature_AddCustomSignature_Title": "Tambahkan tanda tangan khusus", "SettingsSignature_AddCustomSignature_Title": "Tambahkan tanda tangan khusus",
"SettingsSignature_DeleteSignature_Title": "Hapus tanda tangan", "SettingsSignature_DeleteSignature_Title": "Hapus tanda tangan",
@@ -631,6 +651,8 @@
"SettingsThreads_Title": "Utas Percakapan", "SettingsThreads_Title": "Utas Percakapan",
"SettingsUnlinkAccounts_Description": "Hapus tautan antara akun. Ini tidak akan menghapus akun Anda.", "SettingsUnlinkAccounts_Description": "Hapus tautan antara akun. Ini tidak akan menghapus akun Anda.",
"SettingsUnlinkAccounts_Title": "Lepaskan Tautan Akun", "SettingsUnlinkAccounts_Title": "Lepaskan Tautan Akun",
"SettingsMailRendering_ActionLabels_Title": "Action labels",
"SettingsMailRendering_ActionLabels_Description": "Show action labels.",
"SignatureDeleteDialog_Message": "Apakah Anda yakin ingin menghapus tanda tangan \"{0}\"?", "SignatureDeleteDialog_Message": "Apakah Anda yakin ingin menghapus tanda tangan \"{0}\"?",
"SignatureDeleteDialog_Title": "Hapus tanda tangan", "SignatureDeleteDialog_Title": "Hapus tanda tangan",
"SignatureEditorDialog_SignatureName_Placeholder": "Beri nama tanda tangan", "SignatureEditorDialog_SignatureName_Placeholder": "Beri nama tanda tangan",
@@ -676,7 +698,9 @@
"WinoUpgradeDescription": "Wino menawarkan 3 akun secara gratis. Jika Anda membutuhkan lebih dari 3 akun, mohon tingkatkan.", "WinoUpgradeDescription": "Wino menawarkan 3 akun secara gratis. Jika Anda membutuhkan lebih dari 3 akun, mohon tingkatkan.",
"WinoUpgradeMessage": "Tingkatkan ke Akun Tak Terbatas", "WinoUpgradeMessage": "Tingkatkan ke Akun Tak Terbatas",
"WinoUpgradeRemainingAccountsMessage": "{0} dari {1} akun gratis digunakan.", "WinoUpgradeRemainingAccountsMessage": "{0} dari {1} akun gratis digunakan.",
"Yesterday": "Kemarin" "Yesterday": "Kemarin",
"SettingsAppPreferences_EmailSyncInterval_Title": "Email sync interval",
"SettingsAppPreferences_EmailSyncInterval_Description": "Automatic email synchronization interval (minutes). This setting will be applied only after restarting Wino Mail."
} }

Some files were not shown because too many files have changed in this diff Show More