Calendar buttons etc.
This commit is contained in:
@@ -910,19 +910,37 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create day ranges for each flip item until we reach the total days to load.
|
List<DateRange> flipItemRanges = [];
|
||||||
int totalFlipItemCount = (int)Math.Ceiling((double)flipLoadRange.TotalDays / eachFlipItemCount);
|
|
||||||
|
|
||||||
List<DayRangeRenderModel> renderModels = new();
|
if (calendarLoadDirection == CalendarLoadDirection.Replace &&
|
||||||
|
StatePersistanceService.CalendarDisplayType == CalendarDisplayType.Month)
|
||||||
for (int i = 0; i < totalFlipItemCount; i++)
|
|
||||||
{
|
{
|
||||||
var startDate = flipLoadRange.StartDate.AddDays(i * eachFlipItemCount);
|
var previousRange = strategy.GetPreviousDateRange(flipLoadRange, StatePersistanceService.DayDisplayCount);
|
||||||
var endDate = startDate.AddDays(eachFlipItemCount);
|
var nextRange = strategy.GetNextDateRange(flipLoadRange, StatePersistanceService.DayDisplayCount);
|
||||||
|
|
||||||
var range = new DateRange(startDate, endDate);
|
flipItemRanges.Add(previousRange);
|
||||||
|
flipItemRanges.Add(flipLoadRange);
|
||||||
|
flipItemRanges.Add(nextRange);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Create day ranges for each flip item until we reach the total days to load.
|
||||||
|
int totalFlipItemCount = (int)Math.Ceiling((double)flipLoadRange.TotalDays / eachFlipItemCount);
|
||||||
|
|
||||||
|
for (int i = 0; i < totalFlipItemCount; i++)
|
||||||
|
{
|
||||||
|
var startDate = flipLoadRange.StartDate.AddDays(i * eachFlipItemCount);
|
||||||
|
var endDate = startDate.AddDays(eachFlipItemCount);
|
||||||
|
|
||||||
|
flipItemRanges.Add(new DateRange(startDate, endDate));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<DayRangeRenderModel> renderModels = [];
|
||||||
|
|
||||||
|
foreach (var range in flipItemRanges)
|
||||||
|
{
|
||||||
var renderOptions = new CalendarRenderOptions(range, CurrentSettings);
|
var renderOptions = new CalendarRenderOptions(range, CurrentSettings);
|
||||||
|
|
||||||
var dayRangeHeaderModel = new DayRangeRenderModel(renderOptions);
|
var dayRangeHeaderModel = new DayRangeRenderModel(renderOptions);
|
||||||
renderModels.Add(dayRangeHeaderModel);
|
renderModels.Add(dayRangeHeaderModel);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,7 +84,6 @@
|
|||||||
"Buttons_SyncAliases": "Synchronize Aliases",
|
"Buttons_SyncAliases": "Synchronize Aliases",
|
||||||
"Buttons_TryAgain": "Try Again",
|
"Buttons_TryAgain": "Try Again",
|
||||||
"Buttons_Yes": "Yes",
|
"Buttons_Yes": "Yes",
|
||||||
"Purchased": "Purchased",
|
|
||||||
"Sync_SynchronizingFolder": "Synchronizing {0} {1}%",
|
"Sync_SynchronizingFolder": "Synchronizing {0} {1}%",
|
||||||
"Sync_DownloadedMessages": "Downloaded {0} messages from {1}",
|
"Sync_DownloadedMessages": "Downloaded {0} messages from {1}",
|
||||||
"SyncAction_Archiving": "Archiving {0} mail(s)",
|
"SyncAction_Archiving": "Archiving {0} mail(s)",
|
||||||
@@ -830,12 +829,6 @@
|
|||||||
"SettingsHome_StorageCard_Description": "See how much local MIME content Wino keeps on this device and clean it up when needed.",
|
"SettingsHome_StorageCard_Description": "See how much local MIME content Wino keeps on this device and clean it up when needed.",
|
||||||
"SettingsHome_StorageEmptySummary": "No cached MIME content detected yet.",
|
"SettingsHome_StorageEmptySummary": "No cached MIME content detected yet.",
|
||||||
"SettingsHome_StorageLoading": "Checking local MIME usage...",
|
"SettingsHome_StorageLoading": "Checking local MIME usage...",
|
||||||
"SettingsHome_WinoAccount_Title": "Wino Account",
|
|
||||||
"SettingsHome_WinoAccount_SignedOutDescription": "Sign in to sync settings across devices and access add-ons like Wino AI Pack.",
|
|
||||||
"SettingsHome_WinoAccount_ManageLink": "Manage Wino Account",
|
|
||||||
"SettingsHome_AiPack_Title": "Wino AI Pack",
|
|
||||||
"SettingsHome_SettingsSync_Title": "Settings sync",
|
|
||||||
"SettingsHome_SettingsSync_Description": "Export or import your preferences to keep them in sync across devices.",
|
|
||||||
"SettingsHome_Tips_Title": "Tips & tricks",
|
"SettingsHome_Tips_Title": "Tips & tricks",
|
||||||
"SettingsHome_Tips_Description": "A few small changes can make Wino feel much more personal.",
|
"SettingsHome_Tips_Description": "A few small changes can make Wino feel much more personal.",
|
||||||
"SettingsHome_Tip_Theme": "Want dark mode or accent changes? Open Personalization.",
|
"SettingsHome_Tip_Theme": "Want dark mode or accent changes? Open Personalization.",
|
||||||
@@ -856,58 +849,6 @@
|
|||||||
"SettingsSearch_Personalization_Keywords": "theme;dark;light;appearance;accent;color;colour;mode;layout;density",
|
"SettingsSearch_Personalization_Keywords": "theme;dark;light;appearance;accent;color;colour;mode;layout;density",
|
||||||
"SettingsSearch_About_Keywords": "about;version;website;privacy;github;donate;store;support",
|
"SettingsSearch_About_Keywords": "about;version;website;privacy;github;donate;store;support",
|
||||||
"SettingsSearch_KeyboardShortcuts_Keywords": "shortcut;shortcuts;hotkey;hotkeys;keyboard;keys",
|
"SettingsSearch_KeyboardShortcuts_Keywords": "shortcut;shortcuts;hotkey;hotkeys;keyboard;keys",
|
||||||
"SettingsSearch_WinoAccount_Keywords": "winoaccount;account;accounts;wino",
|
|
||||||
"WinoAccount_Management_Description": "Manage your Wino Account, AI Pack access, and synchronized settings.",
|
|
||||||
"WinoAccount_Management_SignedOutTitle": "Sign in to Wino Mail",
|
|
||||||
"WinoAccount_Management_SignedOutDescription": "Sign in or create an account to sync your email, access AI features, and manage your settings across devices.",
|
|
||||||
"WinoAccount_Management_ProfileSectionHeader": "Profile",
|
|
||||||
"WinoAccount_Management_AddOnsSectionHeader": "Wino Add-Ons",
|
|
||||||
"WinoAccount_Management_DataSectionHeader": "Data",
|
|
||||||
"WinoAccount_Management_AccountActionsSectionHeader": "Account actions",
|
|
||||||
"WinoAccount_Management_AccountCardTitle": "Account",
|
|
||||||
"WinoAccount_Management_AccountCardDescription": "Your Wino Account email address and current account state.",
|
|
||||||
"WinoAccount_Management_AiPackCardTitle": "AI Pack",
|
|
||||||
"WinoAccount_Management_AiPackCardDescription": "See whether Wino AI Pack is active and how much usage is left.",
|
|
||||||
"WinoAccount_Management_AiPackActive": "AI Pack is active",
|
|
||||||
"WinoAccount_Management_AiPackInactive": "AI Pack is not active",
|
|
||||||
"WinoAccount_Management_AiPackUsage": "{0} of {1} uses consumed. {2} remaining.",
|
|
||||||
"WinoAccount_Management_AiPackBillingPeriod": "Billing period: {0:d} - {1:d}",
|
|
||||||
"WinoAccount_Management_AiPackUnknownUsage": "Usage details are not available yet.",
|
|
||||||
"WinoAccount_Management_AiPackBuyDescription": "Buy Wino AI Pack to translate, rewrite or summarize emails with AI.",
|
|
||||||
"WinoAccount_Management_AiPackPromoTitle": "Unlock AI Pack",
|
|
||||||
"WinoAccount_Management_AiPackPromoDescription": "Supercharge your email workflow with AI-powered tools. Translate messages into 50+ languages, rewrite for clarity and tone, and get instant summaries of long threads.",
|
|
||||||
"WinoAccount_Management_AiPackPromoPrice": "$4.99 / mo",
|
|
||||||
"WinoAccount_Management_AiPackPromoRequests": "1,000 requests",
|
|
||||||
"WinoAccount_Management_AiPackGetButton": "Get AI Pack",
|
|
||||||
"WinoAccount_Management_PurchaseRequiresSignIn": "Sign in with your Wino Account to complete this purchase.",
|
|
||||||
"WinoAccount_Management_PurchaseStartFailed": "Wino could not start the checkout session for this add-on.",
|
|
||||||
"WinoAccount_Management_AiPackSubscriptionActive": "Your subscription is active",
|
|
||||||
"WinoAccount_Management_AiPackRenews": "Renews {0:d}",
|
|
||||||
"WinoAccount_Management_AiPackRequestsUsed": "Requests used this month",
|
|
||||||
"WinoAccount_Management_AiPackResets": "Resets {0:d}",
|
|
||||||
"WinoAccount_Management_AiPackFeatureTranslate": "Translate",
|
|
||||||
"WinoAccount_Management_AiPackFeatureRewrite": "Rewrite",
|
|
||||||
"WinoAccount_Management_AiPackFeatureSummarize": "Summarize",
|
|
||||||
"WinoAccount_Management_SyncPreferencesTitle": "Synchronize Preferences",
|
|
||||||
"WinoAccount_Management_SyncPreferencesDescription": "Import or export your preferences to cloud. Import them across devices.",
|
|
||||||
"WinoAccount_Management_SignOutTitle": "Sign out",
|
|
||||||
"WinoAccount_Management_SignOutDescription": "Sign out of your account on this device",
|
|
||||||
"WinoAccount_Management_StatusLabel": "Status: {0}",
|
|
||||||
"WinoAccount_Management_NoRemoteSettings": "There are no synchronized settings stored for this account yet.",
|
|
||||||
"WinoAccount_Management_ExportSucceeded": "Your settings were exported to your Wino Account.",
|
|
||||||
"WinoAccount_Management_ImportSucceeded": "Imported {0} settings from your Wino Account.",
|
|
||||||
"WinoAccount_Management_ImportPartial": "Imported {0} settings. {1} settings could not be restored.",
|
|
||||||
"WinoAccount_Management_SerializeFailed": "Wino could not serialize your current preferences.",
|
|
||||||
"WinoAccount_Management_EmptyExport": "There are no preference values to export.",
|
|
||||||
"WinoAccount_Management_ImportEmpty": "The synchronized settings payload does not contain any values to restore.",
|
|
||||||
"WinoAccount_Management_LoadFailed": "Wino could not load the latest Wino Account information.",
|
|
||||||
"WinoAccount_Management_ActionFailed": "The Wino Account request could not be completed.",
|
|
||||||
"WinoAddOn_AI_PACK_Name": "AI Pack",
|
|
||||||
"WinoAddOn_AI_PACK_Description": "Translate, rewrite, and summarize emails with Wino AI.",
|
|
||||||
"WinoAddOn_AI_PACK_Keywords": "Translate · Rewrite · Summarize",
|
|
||||||
"WinoAddOn_UNLIMITED_ACCOUNTS_Name": "Unlimited Accounts",
|
|
||||||
"WinoAddOn_UNLIMITED_ACCOUNTS_Description": "Remove the 3-account limit and add as many accounts as you need.",
|
|
||||||
"WinoAddOn_UNLIMITED_ACCOUNTS_Keywords": "More accounts · No limit · One-time purchase",
|
|
||||||
"SettingsSearch_MessageList_Keywords": "message;messages;list;threading;threads;avatar;preview;sender",
|
"SettingsSearch_MessageList_Keywords": "message;messages;list;threading;threads;avatar;preview;sender",
|
||||||
"SettingsSearch_ReadComposePane_Keywords": "reader;compose;composer;font;fonts;external content;display;reading",
|
"SettingsSearch_ReadComposePane_Keywords": "reader;compose;composer;font;fonts;external content;display;reading",
|
||||||
"SettingsSearch_SignatureAndEncryption_Keywords": "signature;signatures;encryption;certificate;certificates;s mime;smime;security",
|
"SettingsSearch_SignatureAndEncryption_Keywords": "signature;signatures;encryption;certificate;certificates;s mime;smime;security",
|
||||||
@@ -1041,9 +982,8 @@
|
|||||||
"SystemFolderConfigDialogValidation_InboxSelected": "You can't assign Inbox folder to any other system folder.",
|
"SystemFolderConfigDialogValidation_InboxSelected": "You can't assign Inbox folder to any other system folder.",
|
||||||
"SystemFolderConfigSetupSuccess_Message": "System folders are successfully configured.",
|
"SystemFolderConfigSetupSuccess_Message": "System folders are successfully configured.",
|
||||||
"SystemFolderConfigSetupSuccess_Title": "System Folders Setup",
|
"SystemFolderConfigSetupSuccess_Title": "System Folders Setup",
|
||||||
"SystemTrayMenu_Open": "Open",
|
"SystemTrayMenu_ShowWino": "Open Wino Mail",
|
||||||
"SystemTrayMenu_ShowWino": "Open Mail",
|
"SystemTrayMenu_ShowWinoCalendar": "Open Wino Calendar",
|
||||||
"SystemTrayMenu_ShowWinoCalendar": "Open Calendar",
|
|
||||||
"SystemTrayMenu_ExitWino": "Exit",
|
"SystemTrayMenu_ExitWino": "Exit",
|
||||||
"TestingImapConnectionMessage": "Testing server connection...",
|
"TestingImapConnectionMessage": "Testing server connection...",
|
||||||
"TitleBarServerDisconnectedButton_Description": "Wino is disconnected from the network. Click reconnect to restore connection.",
|
"TitleBarServerDisconnectedButton_Description": "Wino is disconnected from the network. Click reconnect to restore connection.",
|
||||||
@@ -1228,10 +1168,6 @@
|
|||||||
"WinoAccount_RegisterDialog_DifferenceTitle": "Wino Account is separate from your mail accounts",
|
"WinoAccount_RegisterDialog_DifferenceTitle": "Wino Account is separate from your mail accounts",
|
||||||
"WinoAccount_RegisterDialog_DifferenceDescription": "Your Outlook, Gmail, IMAP, or other email accounts stay exactly as they are. A Wino Account only manages Wino-specific features and account-based add-ons.",
|
"WinoAccount_RegisterDialog_DifferenceDescription": "Your Outlook, Gmail, IMAP, or other email accounts stay exactly as they are. A Wino Account only manages Wino-specific features and account-based add-ons.",
|
||||||
"WinoAccount_RegisterDialog_PrimaryButton": "Register",
|
"WinoAccount_RegisterDialog_PrimaryButton": "Register",
|
||||||
"WinoAccount_RegisterDialog_PrivacyTitle": "Privacy and API processing",
|
|
||||||
"WinoAccount_RegisterDialog_PrivacyDescription": "Optional add-ons such as Wino AI Pack may send selected email HTML content to the Wino API service only when you use those features.",
|
|
||||||
"WinoAccount_RegisterDialog_PrivacyLinkText": "Read the privacy policy",
|
|
||||||
"WinoAccount_RegisterDialog_PrivacyCheckbox": "I agree to the privacy policy.",
|
|
||||||
"WinoAccount_LoginDialog_Title": "Sign In to Wino Account",
|
"WinoAccount_LoginDialog_Title": "Sign In to Wino Account",
|
||||||
"WinoAccount_LoginDialog_Description": "Sign in to your Wino Account to sync your Wino setup and access account-based features.",
|
"WinoAccount_LoginDialog_Description": "Sign in to your Wino Account to sync your Wino setup and access account-based features.",
|
||||||
"WinoAccount_LoginDialog_HeroTitle": "Welcome back",
|
"WinoAccount_LoginDialog_HeroTitle": "Welcome back",
|
||||||
@@ -1239,28 +1175,17 @@
|
|||||||
"WinoAccount_LoginDialog_BenefitsDescription": "Use your Wino Account to continue syncing settings across devices and to access paid add-ons such as Wino AI Pack.",
|
"WinoAccount_LoginDialog_BenefitsDescription": "Use your Wino Account to continue syncing settings across devices and to access paid add-ons such as Wino AI Pack.",
|
||||||
"WinoAccount_LoginDialog_DifferenceTitle": "This is not your email mailbox sign-in",
|
"WinoAccount_LoginDialog_DifferenceTitle": "This is not your email mailbox sign-in",
|
||||||
"WinoAccount_LoginDialog_DifferenceDescription": "Signing in here does not add or replace your Outlook, Gmail, or IMAP accounts in Wino. It only signs you in to Wino-specific services.",
|
"WinoAccount_LoginDialog_DifferenceDescription": "Signing in here does not add or replace your Outlook, Gmail, or IMAP accounts in Wino. It only signs you in to Wino-specific services.",
|
||||||
"WinoAccount_LoginDialog_ForgotPasswordLink": "Forgot password?",
|
|
||||||
"WinoAccount_EmailLabel": "Email",
|
"WinoAccount_EmailLabel": "Email",
|
||||||
"WinoAccount_EmailPlaceholder": "name@example.com",
|
"WinoAccount_EmailPlaceholder": "name@example.com",
|
||||||
"WinoAccount_PasswordLabel": "Password",
|
"WinoAccount_PasswordLabel": "Password",
|
||||||
"WinoAccount_ConfirmPasswordLabel": "Confirm password",
|
"WinoAccount_ConfirmPasswordLabel": "Confirm password",
|
||||||
"WinoAccount_ForgotPasswordDialog_Title": "Reset your password",
|
|
||||||
"WinoAccount_ForgotPasswordDialog_PrimaryButton": "Send reset email",
|
|
||||||
"WinoAccount_ForgotPasswordDialog_BackToSignIn": "Back to sign in",
|
|
||||||
"WinoAccount_ForgotPasswordDialog_Description": "Enter your Wino Account email address and we will send you a password reset link if the address is registered.",
|
|
||||||
"WinoAccount_Validation_EmailRequired": "Email is required.",
|
"WinoAccount_Validation_EmailRequired": "Email is required.",
|
||||||
"WinoAccount_Validation_PasswordRequired": "Password is required.",
|
"WinoAccount_Validation_PasswordRequired": "Password is required.",
|
||||||
"WinoAccount_Validation_PasswordMismatch": "Passwords do not match.",
|
"WinoAccount_Validation_PasswordMismatch": "Passwords do not match.",
|
||||||
"WinoAccount_Validation_PrivacyConsentRequired": "You must accept the privacy policy before creating a Wino Account.",
|
|
||||||
"WinoAccount_Error_InvalidCredentials": "The email address or password is incorrect.",
|
"WinoAccount_Error_InvalidCredentials": "The email address or password is incorrect.",
|
||||||
"WinoAccount_Error_AccountLocked": "This account is temporarily locked.",
|
"WinoAccount_Error_AccountLocked": "This account is temporarily locked.",
|
||||||
"WinoAccount_Error_AccountBanned": "This account has been banned.",
|
"WinoAccount_Error_AccountBanned": "This account has been banned.",
|
||||||
"WinoAccount_Error_AccountSuspended": "This account has been suspended.",
|
"WinoAccount_Error_AccountSuspended": "This account has been suspended.",
|
||||||
"WinoAccount_Error_EmailNotConfirmed": "Please confirm your email address before signing in.",
|
|
||||||
"WinoAccount_Error_EmailConfirmationRequired": "Please confirm your email address before signing in.",
|
|
||||||
"WinoAccount_Error_EmailConfirmationResendNotAvailable": "A new confirmation email is not available yet.",
|
|
||||||
"WinoAccount_Error_EmailConfirmationResendInvalid": "This confirmation request is no longer valid. Please try signing in again.",
|
|
||||||
"WinoAccount_Error_EmailNotRegistered": "This email address is not registered.",
|
|
||||||
"WinoAccount_Error_RefreshTokenInvalid": "Your session is no longer valid. Please sign in again.",
|
"WinoAccount_Error_RefreshTokenInvalid": "Your session is no longer valid. Please sign in again.",
|
||||||
"WinoAccount_Error_EmailAlreadyRegistered": "This email address is already registered.",
|
"WinoAccount_Error_EmailAlreadyRegistered": "This email address is already registered.",
|
||||||
"WinoAccount_Error_ExternalLoginEmailRequired": "An email address is required to complete external sign-in.",
|
"WinoAccount_Error_ExternalLoginEmailRequired": "An email address is required to complete external sign-in.",
|
||||||
@@ -1271,21 +1196,6 @@
|
|||||||
"WinoAccount_Error_ValidationFailed": "The request is invalid. Please review the entered values.",
|
"WinoAccount_Error_ValidationFailed": "The request is invalid. Please review the entered values.",
|
||||||
"WinoAccount_RegisterSuccessMessage": "Wino Account registration completed for {0}.",
|
"WinoAccount_RegisterSuccessMessage": "Wino Account registration completed for {0}.",
|
||||||
"WinoAccount_LoginSuccessMessage": "Signed in to Wino Account as {0}.",
|
"WinoAccount_LoginSuccessMessage": "Signed in to Wino Account as {0}.",
|
||||||
"WinoAccount_EmailConfirmationSentDialog_Title": "Confirm your email address",
|
|
||||||
"WinoAccount_EmailConfirmationSentDialog_Message": "We sent an email confirmation to {0}. Please confirm it and try signing in again.",
|
|
||||||
"WinoAccount_EmailConfirmationPendingDialog_Title": "Email confirmation required",
|
|
||||||
"WinoAccount_EmailConfirmationPendingDialog_Message": "We are still waiting for you to confirm {0}.",
|
|
||||||
"WinoAccount_EmailConfirmationPendingDialog_ResendButton": "Resend confirmation email",
|
|
||||||
"WinoAccount_EmailConfirmationPendingDialog_Countdown": "You can resend the confirmation email in {0}.",
|
|
||||||
"WinoAccount_EmailConfirmationPendingDialog_ReadyToResend": "You can resend the confirmation email now.",
|
|
||||||
"WinoAccount_EmailConfirmationResentDialog_Title": "Confirmation email resent",
|
|
||||||
"WinoAccount_EmailConfirmationResentDialog_Message": "We sent another confirmation email to {0}. Please confirm it and try signing in again.",
|
|
||||||
"WinoAccount_ForgotPasswordDialog_SuccessTitle": "Password reset email sent",
|
|
||||||
"WinoAccount_ForgotPasswordDialog_SuccessMessage": "We sent a password reset email to {0}. Open that message to choose a new password.",
|
|
||||||
"WinoAccount_ChangePassword_Title": "Change password",
|
|
||||||
"WinoAccount_ChangePassword_Description": "Send a password reset email to this Wino Account.",
|
|
||||||
"WinoAccount_ChangePassword_Action": "Send reset email",
|
|
||||||
"WinoAccount_ChangePassword_ConfirmationMessage": "Do you want Wino to send a password reset email to {0}?",
|
|
||||||
"WinoAccount_SignOut_SuccessMessage": "Signed out from Wino Account {0}.",
|
"WinoAccount_SignOut_SuccessMessage": "Signed out from Wino Account {0}.",
|
||||||
"WinoAccount_SignOut_NoAccountMessage": "There is no active Wino Account to sign out.",
|
"WinoAccount_SignOut_NoAccountMessage": "There is no active Wino Account to sign out.",
|
||||||
"WinoAccount_Titlebar_SignedOutTitle": "Wino Account",
|
"WinoAccount_Titlebar_SignedOutTitle": "Wino Account",
|
||||||
|
|||||||
@@ -11,26 +11,18 @@ using Wino.Core.Domain.Entities.Shared;
|
|||||||
using Wino.Core.Domain.Enums;
|
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.Domain.Models.Accounts;
|
|
||||||
using Wino.Core.Domain.Models.Personalization;
|
using Wino.Core.Domain.Models.Personalization;
|
||||||
using Wino.Core.Domain.Models.Settings;
|
using Wino.Core.Domain.Models.Settings;
|
||||||
using Wino.Core.Domain.Models.Translations;
|
using Wino.Core.Domain.Models.Translations;
|
||||||
using Wino.Core.Extensions;
|
using Wino.Core.Extensions;
|
||||||
using Wino.Core.ViewModels.Data;
|
using Wino.Core.ViewModels.Data;
|
||||||
using Wino.Mail.Api.Contracts.Ai;
|
|
||||||
using Wino.Mail.ViewModels.Data;
|
using Wino.Mail.ViewModels.Data;
|
||||||
using Wino.Messaging.Client.Navigation;
|
using Wino.Messaging.Client.Navigation;
|
||||||
using Wino.Messaging.UI;
|
|
||||||
|
|
||||||
namespace Wino.Core.ViewModels;
|
namespace Wino.Core.ViewModels;
|
||||||
|
|
||||||
public partial class SettingOptionsPageViewModel : CoreBaseViewModel,
|
public partial class SettingOptionsPageViewModel : CoreBaseViewModel
|
||||||
IRecipient<WinoAccountProfileUpdatedMessage>,
|
|
||||||
IRecipient<WinoAccountProfileDeletedMessage>,
|
|
||||||
IRecipient<WinoAccountAddOnPurchasedMessage>
|
|
||||||
{
|
{
|
||||||
private const string BuyAiPackUrl = "https://example.com/wino-ai-pack";
|
|
||||||
|
|
||||||
private readonly INativeAppService _nativeAppService;
|
private readonly INativeAppService _nativeAppService;
|
||||||
private readonly IAccountService _accountService;
|
private readonly IAccountService _accountService;
|
||||||
private readonly IMimeStorageService _mimeStorageService;
|
private readonly IMimeStorageService _mimeStorageService;
|
||||||
@@ -39,8 +31,6 @@ public partial class SettingOptionsPageViewModel : CoreBaseViewModel,
|
|||||||
private readonly INewThemeService _newThemeService;
|
private readonly INewThemeService _newThemeService;
|
||||||
private readonly IPreferencesService _preferencesService;
|
private readonly IPreferencesService _preferencesService;
|
||||||
private readonly IProviderService _providerService;
|
private readonly IProviderService _providerService;
|
||||||
private readonly IWinoAccountProfileService _profileService;
|
|
||||||
private readonly IMailDialogService _dialogService;
|
|
||||||
private bool _isInitializingSettings;
|
private bool _isInitializingSettings;
|
||||||
private bool _isAppearanceSelectionPaused;
|
private bool _isAppearanceSelectionPaused;
|
||||||
|
|
||||||
@@ -92,42 +82,6 @@ public partial class SettingOptionsPageViewModel : CoreBaseViewModel,
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public partial bool UseAccentColor { get; set; }
|
public partial bool UseAccentColor { get; set; }
|
||||||
|
|
||||||
// Wino Account hero card properties
|
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
public partial bool IsWinoAccountBusy { get; set; }
|
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
[NotifyPropertyChangedFor(nameof(IsWinoAccountSignedOut))]
|
|
||||||
[NotifyPropertyChangedFor(nameof(CanShowBuyAiPack))]
|
|
||||||
public partial bool IsWinoAccountSignedIn { get; set; }
|
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
public partial string WinoAccountEmail { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
public partial string WinoAccountStatusText { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
[NotifyPropertyChangedFor(nameof(CanShowBuyAiPack))]
|
|
||||||
public partial bool HasAiPack { get; set; }
|
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
public partial string AiPackStateText { get; set; } = Translator.WinoAccount_Management_AiPackInactive;
|
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
public partial string AiUsageSummary { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
public partial string AiBillingPeriodSummary { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
public partial double AiUsagePercent { get; set; }
|
|
||||||
|
|
||||||
public bool IsWinoAccountSignedOut => !IsWinoAccountSignedIn;
|
|
||||||
public bool CanShowAiUsage => HasAiPack;
|
|
||||||
public bool CanShowBuyAiPack => IsWinoAccountSignedIn && !HasAiPack;
|
|
||||||
|
|
||||||
public SettingOptionsPageViewModel(INativeAppService nativeAppService,
|
public SettingOptionsPageViewModel(INativeAppService nativeAppService,
|
||||||
IAccountService accountService,
|
IAccountService accountService,
|
||||||
IMimeStorageService mimeStorageService,
|
IMimeStorageService mimeStorageService,
|
||||||
@@ -135,9 +89,7 @@ public partial class SettingOptionsPageViewModel : CoreBaseViewModel,
|
|||||||
ITranslationService translationService,
|
ITranslationService translationService,
|
||||||
INewThemeService newThemeService,
|
INewThemeService newThemeService,
|
||||||
IPreferencesService preferencesService,
|
IPreferencesService preferencesService,
|
||||||
IProviderService providerService,
|
IProviderService providerService)
|
||||||
IWinoAccountProfileService profileService,
|
|
||||||
IMailDialogService dialogService)
|
|
||||||
{
|
{
|
||||||
_nativeAppService = nativeAppService;
|
_nativeAppService = nativeAppService;
|
||||||
_accountService = accountService;
|
_accountService = accountService;
|
||||||
@@ -147,8 +99,6 @@ public partial class SettingOptionsPageViewModel : CoreBaseViewModel,
|
|||||||
_newThemeService = newThemeService;
|
_newThemeService = newThemeService;
|
||||||
_preferencesService = preferencesService;
|
_preferencesService = preferencesService;
|
||||||
_providerService = providerService;
|
_providerService = providerService;
|
||||||
_profileService = profileService;
|
|
||||||
_dialogService = dialogService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnNavigatedTo(NavigationMode mode, object parameters)
|
public override void OnNavigatedTo(NavigationMode mode, object parameters)
|
||||||
@@ -162,7 +112,6 @@ public partial class SettingOptionsPageViewModel : CoreBaseViewModel,
|
|||||||
InitializeQuickSettings();
|
InitializeQuickSettings();
|
||||||
|
|
||||||
_ = LoadDashboardAsync();
|
_ = LoadDashboardAsync();
|
||||||
_ = LoadWinoAccountAsync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateSearchSuggestions(string query)
|
public void UpdateSearchSuggestions(string query)
|
||||||
@@ -416,212 +365,6 @@ public partial class SettingOptionsPageViewModel : CoreBaseViewModel,
|
|||||||
await _translationService.InitializeLanguageAsync(language.Language);
|
await _translationService.InitializeLanguageAsync(language.Language);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wino Account message recipients
|
|
||||||
|
|
||||||
protected override void RegisterRecipients()
|
|
||||||
{
|
|
||||||
base.RegisterRecipients();
|
|
||||||
|
|
||||||
Messenger.Register<WinoAccountProfileUpdatedMessage>(this);
|
|
||||||
Messenger.Register<WinoAccountProfileDeletedMessage>(this);
|
|
||||||
Messenger.Register<WinoAccountAddOnPurchasedMessage>(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void UnregisterRecipients()
|
|
||||||
{
|
|
||||||
base.UnregisterRecipients();
|
|
||||||
|
|
||||||
Messenger.Unregister<WinoAccountProfileUpdatedMessage>(this);
|
|
||||||
Messenger.Unregister<WinoAccountProfileDeletedMessage>(this);
|
|
||||||
Messenger.Unregister<WinoAccountAddOnPurchasedMessage>(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Receive(WinoAccountProfileUpdatedMessage message)
|
|
||||||
=> _ = LoadWinoAccountAsync();
|
|
||||||
|
|
||||||
public void Receive(WinoAccountProfileDeletedMessage message)
|
|
||||||
=> _ = ResetWinoAccountStateAsync();
|
|
||||||
|
|
||||||
public void Receive(WinoAccountAddOnPurchasedMessage message)
|
|
||||||
=> _ = LoadWinoAccountAsync();
|
|
||||||
|
|
||||||
// Wino Account hero card commands and helpers
|
|
||||||
|
|
||||||
[RelayCommand]
|
|
||||||
private async Task WinoAccountRegisterAsync()
|
|
||||||
{
|
|
||||||
var account = await _dialogService.ShowWinoAccountRegistrationDialogAsync();
|
|
||||||
if (account == null) return;
|
|
||||||
|
|
||||||
_dialogService.InfoBarMessage(Translator.GeneralTitle_Info,
|
|
||||||
string.Format(Translator.WinoAccount_RegisterSuccessMessage, account.Email),
|
|
||||||
InfoBarMessageType.Success);
|
|
||||||
await LoadWinoAccountAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
[RelayCommand]
|
|
||||||
private async Task WinoAccountSignInAsync()
|
|
||||||
{
|
|
||||||
var account = await _dialogService.ShowWinoAccountLoginDialogAsync();
|
|
||||||
if (account == null) return;
|
|
||||||
|
|
||||||
_dialogService.InfoBarMessage(Translator.GeneralTitle_Info,
|
|
||||||
string.Format(Translator.WinoAccount_LoginSuccessMessage, account.Email),
|
|
||||||
InfoBarMessageType.Success);
|
|
||||||
await LoadWinoAccountAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
[RelayCommand]
|
|
||||||
private async Task WinoAccountSignOutAsync()
|
|
||||||
{
|
|
||||||
var account = await _profileService.GetActiveAccountAsync().ConfigureAwait(false);
|
|
||||||
if (account == null) return;
|
|
||||||
|
|
||||||
await _profileService.SignOutAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
_dialogService.InfoBarMessage(Translator.GeneralTitle_Info,
|
|
||||||
string.Format(Translator.WinoAccount_SignOut_SuccessMessage, account.Email),
|
|
||||||
InfoBarMessageType.Success);
|
|
||||||
await ResetWinoAccountStateAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
[RelayCommand]
|
|
||||||
private async Task OpenBuyAiPackPageAsync() => await _nativeAppService.LaunchUriAsync(new Uri(BuyAiPackUrl));
|
|
||||||
|
|
||||||
[RelayCommand]
|
|
||||||
private void NavigateToWinoAccountManagement()
|
|
||||||
=> NavigateSubDetail(WinoPage.WinoAccountManagementPage);
|
|
||||||
|
|
||||||
private async Task LoadWinoAccountAsync()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var cachedAccount = await _profileService.GetActiveAccountAsync().ConfigureAwait(false);
|
|
||||||
var cachedAddOns = await _profileService.GetCachedAddOnSnapshotAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (cachedAccount != null)
|
|
||||||
{
|
|
||||||
await ApplyWinoAccountStateAsync(cachedAccount.Email, cachedAccount.AccountStatus).ConfigureAwait(false);
|
|
||||||
UpdateAiPackState(cachedAddOns);
|
|
||||||
}
|
|
||||||
|
|
||||||
await ExecuteUIThread(() => IsWinoAccountBusy = cachedAccount == null);
|
|
||||||
|
|
||||||
var account = await _profileService.GetAuthenticatedAccountAsync().ConfigureAwait(false);
|
|
||||||
if (account == null)
|
|
||||||
{
|
|
||||||
await ResetWinoAccountStateAsync();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var aiStatusResponse = await _profileService.GetAiStatusAsync().ConfigureAwait(false);
|
|
||||||
var profileRefreshResult = await _profileService.RefreshProfileAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
var resolvedAccount = profileRefreshResult.IsSuccess && profileRefreshResult.Account != null
|
|
||||||
? profileRefreshResult.Account
|
|
||||||
: account;
|
|
||||||
|
|
||||||
await ApplyWinoAccountStateAsync(resolvedAccount.Email, resolvedAccount.AccountStatus).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (aiStatusResponse.IsSuccess)
|
|
||||||
{
|
|
||||||
UpdateAiPackState(aiStatusResponse.Result);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UpdateAiPackState(cachedAddOns);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
await ResetWinoAccountStateAsync();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
await ExecuteUIThread(() => IsWinoAccountBusy = false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ApplyWinoAccountStateAsync(string email, string status)
|
|
||||||
{
|
|
||||||
await ExecuteUIThread(() =>
|
|
||||||
{
|
|
||||||
IsWinoAccountSignedIn = true;
|
|
||||||
WinoAccountEmail = email;
|
|
||||||
WinoAccountStatusText = string.Format(Translator.WinoAccount_Management_StatusLabel, status);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ResetWinoAccountStateAsync()
|
|
||||||
{
|
|
||||||
await ExecuteUIThread(() =>
|
|
||||||
{
|
|
||||||
IsWinoAccountSignedIn = false;
|
|
||||||
WinoAccountEmail = string.Empty;
|
|
||||||
WinoAccountStatusText = string.Empty;
|
|
||||||
HasAiPack = false;
|
|
||||||
AiPackStateText = Translator.WinoAccount_Management_AiPackInactive;
|
|
||||||
AiUsageSummary = string.Empty;
|
|
||||||
AiBillingPeriodSummary = string.Empty;
|
|
||||||
AiUsagePercent = 0;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateAiPackState(AiStatusResultDto aiStatus)
|
|
||||||
{
|
|
||||||
UpdateAiPackState(
|
|
||||||
aiStatus?.HasAiPack == true,
|
|
||||||
aiStatus?.Used,
|
|
||||||
aiStatus?.MonthlyLimit,
|
|
||||||
aiStatus?.Remaining,
|
|
||||||
aiStatus?.CurrentPeriodStartUtc,
|
|
||||||
aiStatus?.CurrentPeriodEndUtc);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateAiPackState(WinoAccountAddOnSnapshot addOnSnapshot)
|
|
||||||
{
|
|
||||||
var remaining = addOnSnapshot?.HasAiPack == true && addOnSnapshot.UsageLimit is int limit && addOnSnapshot.UsageCount is int used
|
|
||||||
? limit - used
|
|
||||||
: (int?)null;
|
|
||||||
|
|
||||||
UpdateAiPackState(
|
|
||||||
addOnSnapshot?.HasAiPack == true,
|
|
||||||
addOnSnapshot?.UsageCount,
|
|
||||||
addOnSnapshot?.UsageLimit,
|
|
||||||
remaining,
|
|
||||||
addOnSnapshot?.BillingPeriodStartUtc,
|
|
||||||
addOnSnapshot?.BillingPeriodEndUtc);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateAiPackState(bool hasAiPack, int? used, int? limit, int? remaining, DateTimeOffset? periodStart, DateTimeOffset? periodEnd)
|
|
||||||
{
|
|
||||||
var usageText = Translator.WinoAccount_Management_AiPackUnknownUsage;
|
|
||||||
var billingText = string.Empty;
|
|
||||||
var usagePercent = 0d;
|
|
||||||
|
|
||||||
if (hasAiPack && used is int usageCount && limit is int usageLimit && remaining is int remainingCount)
|
|
||||||
{
|
|
||||||
usageText = string.Format(Translator.WinoAccount_Management_AiPackUsage, usageCount, usageLimit, remainingCount);
|
|
||||||
usagePercent = usageLimit > 0 ? (double)usageCount / usageLimit * 100 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasAiPack && periodStart is DateTimeOffset billingStart && periodEnd is DateTimeOffset billingEnd)
|
|
||||||
{
|
|
||||||
billingText = string.Format(Translator.WinoAccount_Management_AiPackBillingPeriod, billingStart.LocalDateTime, billingEnd.LocalDateTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = ExecuteUIThread(() =>
|
|
||||||
{
|
|
||||||
HasAiPack = hasAiPack;
|
|
||||||
AiPackStateText = hasAiPack
|
|
||||||
? Translator.WinoAccount_Management_AiPackActive
|
|
||||||
: Translator.WinoAccount_Management_AiPackInactive;
|
|
||||||
AiUsageSummary = hasAiPack ? usageText : string.Empty;
|
|
||||||
AiBillingPeriodSummary = hasAiPack ? billingText : string.Empty;
|
|
||||||
AiUsagePercent = usagePercent;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
public void NavigateSubDetail(object type)
|
public void NavigateSubDetail(object type)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -38,10 +38,7 @@ public partial class CustomCalendarFlipView : FlipView
|
|||||||
{
|
{
|
||||||
base.OnApplyTemplate();
|
base.OnApplyTemplate();
|
||||||
|
|
||||||
PreviousButtonHorizontal = GetTemplateChild(PART_PreviousButtonHorizontal) as Button;
|
RefreshNavigationButtons();
|
||||||
NextButtonHorizontal = GetTemplateChild(PART_NextButtonHorizontal) as Button;
|
|
||||||
PreviousButtonVertical = GetTemplateChild(PART_PreviousButtonVertical) as Button;
|
|
||||||
NextButtonVertical = GetTemplateChild(PART_NextButtonVertical) as Button;
|
|
||||||
|
|
||||||
// Hide navigation buttons
|
// Hide navigation buttons
|
||||||
HideButton(PreviousButtonHorizontal);
|
HideButton(PreviousButtonHorizontal);
|
||||||
@@ -78,25 +75,47 @@ public partial class CustomCalendarFlipView : FlipView
|
|||||||
|
|
||||||
public void GoPreviousFlip()
|
public void GoPreviousFlip()
|
||||||
{
|
{
|
||||||
var previousButton = DisplayType == CalendarDisplayType.Month
|
InvokeNavigationButton(PreviousButtonHorizontal, PreviousButtonVertical);
|
||||||
? PreviousButtonVertical ?? PreviousButtonHorizontal
|
|
||||||
: PreviousButtonHorizontal ?? PreviousButtonVertical;
|
|
||||||
|
|
||||||
if (previousButton == null) return;
|
|
||||||
|
|
||||||
var backPeer = new ButtonAutomationPeer(previousButton);
|
|
||||||
backPeer.Invoke();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GoNextFlip()
|
public void GoNextFlip()
|
||||||
{
|
{
|
||||||
var nextButton = DisplayType == CalendarDisplayType.Month
|
InvokeNavigationButton(NextButtonHorizontal, NextButtonVertical);
|
||||||
? NextButtonVertical ?? NextButtonHorizontal
|
}
|
||||||
: NextButtonHorizontal ?? NextButtonVertical;
|
|
||||||
|
|
||||||
if (nextButton == null) return;
|
private void RefreshNavigationButtons()
|
||||||
|
{
|
||||||
|
PreviousButtonHorizontal = GetTemplateChild(PART_PreviousButtonHorizontal) as Button;
|
||||||
|
NextButtonHorizontal = GetTemplateChild(PART_NextButtonHorizontal) as Button;
|
||||||
|
PreviousButtonVertical = GetTemplateChild(PART_PreviousButtonVertical) as Button;
|
||||||
|
NextButtonVertical = GetTemplateChild(PART_NextButtonVertical) as Button;
|
||||||
|
}
|
||||||
|
|
||||||
var nextPeer = new ButtonAutomationPeer(nextButton);
|
private void InvokeNavigationButton(Button? primaryButton, Button? secondaryButton)
|
||||||
nextPeer.Invoke();
|
{
|
||||||
|
if (Items == null || Items.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
RefreshNavigationButtons();
|
||||||
|
|
||||||
|
var previousIndex = SelectedIndex;
|
||||||
|
|
||||||
|
if (TryInvokeNavigationButton(primaryButton, previousIndex))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TryInvokeNavigationButton(secondaryButton, previousIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryInvokeNavigationButton(Button? navigationButton, int previousIndex)
|
||||||
|
{
|
||||||
|
if (navigationButton == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var peer = new ButtonAutomationPeer(navigationButton);
|
||||||
|
peer.Invoke();
|
||||||
|
|
||||||
|
return SelectedIndex != previousIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,27 +92,17 @@
|
|||||||
BorderBrush="Transparent"
|
BorderBrush="Transparent"
|
||||||
Visibility="{x:Bind helpers:XamlHelpers.ReverseBoolToVisibilityConverter(PreferencesService.IsWinoAccountButtonHidden), Mode=OneWay}">
|
Visibility="{x:Bind helpers:XamlHelpers.ReverseBoolToVisibilityConverter(PreferencesService.IsWinoAccountButtonHidden), Mode=OneWay}">
|
||||||
<Button.Flyout>
|
<Button.Flyout>
|
||||||
<Flyout
|
<Flyout x:Name="WinoAccountFlyout" Placement="Bottom">
|
||||||
x:Name="WinoAccountFlyout"
|
|
||||||
Placement="Bottom">
|
|
||||||
<Grid MinWidth="320" MaxWidth="360">
|
<Grid MinWidth="320" MaxWidth="360">
|
||||||
<StackPanel
|
<StackPanel x:Name="WinoAccountSignedOutView" Spacing="12">
|
||||||
x:Name="WinoAccountSignedOutView"
|
<TextBlock Style="{StaticResource BodyStrongTextBlockStyle}" Text="{x:Bind domain:Translator.WinoAccount_Titlebar_SignedOutTitle}" />
|
||||||
Spacing="12">
|
|
||||||
<TextBlock
|
|
||||||
Style="{StaticResource BodyStrongTextBlockStyle}"
|
|
||||||
Text="{x:Bind domain:Translator.WinoAccount_Titlebar_SignedOutTitle}" />
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||||
Text="{x:Bind domain:Translator.WinoAccount_Titlebar_SignedOutDescription}"
|
Text="{x:Bind domain:Translator.WinoAccount_Titlebar_SignedOutDescription}"
|
||||||
TextWrapping="WrapWholeWords" />
|
TextWrapping="WrapWholeWords" />
|
||||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||||
<Button
|
<Button Click="RegisterWinoAccountClicked" Content="{x:Bind domain:Translator.WinoAccount_RegisterButton_Action}" />
|
||||||
Click="RegisterWinoAccountClicked"
|
<Button Click="LoginWinoAccountClicked" Content="{x:Bind domain:Translator.WinoAccount_LoginButton_Action}" />
|
||||||
Content="{x:Bind domain:Translator.WinoAccount_RegisterButton_Action}" />
|
|
||||||
<Button
|
|
||||||
Click="LoginWinoAccountClicked"
|
|
||||||
Content="{x:Bind domain:Translator.WinoAccount_LoginButton_Action}" />
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
@@ -155,13 +145,12 @@
|
|||||||
<Border
|
<Border
|
||||||
x:Name="WinoAccountSignedOutIcon"
|
x:Name="WinoAccountSignedOutIcon"
|
||||||
Width="30"
|
Width="30"
|
||||||
Height="30"
|
Height="30">
|
||||||
Background="{ThemeResource AccentFillColorDefaultBrush}"
|
<Image Source="/Assets/AppEntries/MailAssets/Square150x150Logo.png" />
|
||||||
CornerRadius="15">
|
<!--<FontIcon
|
||||||
<FontIcon
|
|
||||||
FontSize="16"
|
FontSize="16"
|
||||||
Foreground="White"
|
Foreground="White"
|
||||||
Glyph="" />
|
Glyph="" />-->
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -63,87 +63,6 @@
|
|||||||
</Style>
|
</Style>
|
||||||
</Page.Resources>
|
</Page.Resources>
|
||||||
|
|
||||||
<abstract:CalendarAppShellAbstract.ShellContent>
|
|
||||||
<Grid
|
|
||||||
Margin="4,0,0,0"
|
|
||||||
Background="Transparent"
|
|
||||||
ColumnSpacing="12">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<Grid x:Name="ShellContentArea" ColumnSpacing="12">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
|
|
||||||
<StackPanel
|
|
||||||
x:Name="NavigationTitleStack"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="0,0,12,4"
|
|
||||||
Orientation="Horizontal"
|
|
||||||
Spacing="6">
|
|
||||||
<Button
|
|
||||||
x:Name="PreviousDateButton"
|
|
||||||
Click="PreviousDateClicked"
|
|
||||||
Style="{StaticResource CalendarNavigationButtonStyle}">
|
|
||||||
<PathIcon x:Name="PreviousDateButtonPathIcon" Data="F1 M 8.72 18.599998 C 8.879999 18.733334 9.059999 18.799999 9.26 18.799999 C 9.459999 18.799999 9.633332 18.719999 9.78 18.559999 C 9.926666 18.4 10 18.219999 10 18.019999 C 10 17.82 9.92 17.653332 9.76 17.52 L 4.52 12.559999 L 17.24 12.559999 C 17.453333 12.559999 17.633331 12.486667 17.779999 12.339999 C 17.926666 12.193334 18 12.013333 18 11.799999 C 18 11.586666 17.926666 11.406667 17.779999 11.259999 C 17.633331 11.113333 17.453333 11.039999 17.24 11.039999 L 4.52 11.039999 L 9.76 6.08 C 9.973333 5.893333 10.046666 5.653332 9.98 5.359999 C 9.913333 5.066666 9.74 4.880001 9.46 4.799999 C 9.179999 4.720001 8.933332 4.786667 8.72 5 L 2.32 11.08 C 2.16 11.24 2.053333 11.426666 2 11.639999 C 1.973333 11.746666 1.973333 11.853333 2 11.959999 C 2.053333 12.173333 2.16 12.360001 2.32 12.52 Z " />
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
x:Name="NextDateButton"
|
|
||||||
Click="NextDateClicked"
|
|
||||||
Style="{StaticResource CalendarNavigationButtonStyle}">
|
|
||||||
<PathIcon x:Name="NextDateButtonPathIcon" Data="F1 M 11.28 5 C 11.12 4.866667 10.94 4.806667 10.74 4.82 C 10.539999 4.833334 10.366666 4.913334 10.219999 5.059999 C 10.073333 5.206665 10 5.379999 10 5.58 C 10 5.779999 10.08 5.946667 10.24 6.08 L 15.48 11.039999 L 2.76 11.039999 C 2.546667 11.039999 2.366667 11.113333 2.22 11.259999 C 2.073333 11.406667 2 11.586666 2 11.799999 C 2 12.013333 2.073333 12.193334 2.22 12.339999 C 2.366667 12.486667 2.546667 12.559999 2.76 12.559999 L 15.48 12.559999 L 10.24 17.52 C 10.026667 17.706665 9.953333 17.946667 10.02 18.24 C 10.086666 18.533333 10.259999 18.719999 10.54 18.799999 C 10.82 18.879999 11.066667 18.813334 11.28 18.599998 L 17.68 12.52 C 17.84 12.360001 17.946667 12.173333 18 11.959999 C 18 11.853333 18 11.746666 18 11.639999 C 17.946667 11.426666 17.84 11.24 17.68 11.08 Z " />
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<calendarControls:CustomCalendarFlipView
|
|
||||||
x:Name="DayHeaderNavigationItemsFlipView"
|
|
||||||
MaxHeight="30"
|
|
||||||
Margin="8,4,0,0"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
HorizontalContentAlignment="Left"
|
|
||||||
Background="Transparent"
|
|
||||||
DisplayType="{x:Bind ViewModel.StatePersistenceService.CalendarDisplayType, Mode=OneWay}"
|
|
||||||
FontSize="14"
|
|
||||||
FontWeight="Normal"
|
|
||||||
IsHitTestVisible="False"
|
|
||||||
ItemsSource="{x:Bind ViewModel.DateNavigationHeaderItems}"
|
|
||||||
SelectedIndex="{x:Bind ViewModel.SelectedDateNavigationHeaderIndex, Mode=OneWay}">
|
|
||||||
<FlipView.ItemTemplate>
|
|
||||||
<DataTemplate x:DataType="x:String">
|
|
||||||
<TextBlock
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
FontSize="18"
|
|
||||||
Style="{StaticResource BodyTextBlockStyle}"
|
|
||||||
Text="{x:Bind}" />
|
|
||||||
</DataTemplate>
|
|
||||||
</FlipView.ItemTemplate>
|
|
||||||
</calendarControls:CustomCalendarFlipView>
|
|
||||||
</StackPanel>
|
|
||||||
<AutoSuggestBox
|
|
||||||
x:Name="SearchBox"
|
|
||||||
Grid.Column="1"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
BorderBrush="Transparent"
|
|
||||||
PlaceholderText="Search" />
|
|
||||||
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<calendarControls:WinoCalendarTypeSelectorControl
|
|
||||||
x:Name="CalendarTypeSelector"
|
|
||||||
Grid.Column="2"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
DisplayDayCount="{x:Bind ViewModel.StatePersistenceService.DayDisplayCount, Mode=OneWay}"
|
|
||||||
SelectedType="{x:Bind ViewModel.StatePersistenceService.CalendarDisplayType, Mode=TwoWay}"
|
|
||||||
TodayClickedCommand="{x:Bind ViewModel.TodayClickedCommand}" />
|
|
||||||
</Grid>
|
|
||||||
</abstract:CalendarAppShellAbstract.ShellContent>
|
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="RootGrid"
|
x:Name="RootGrid"
|
||||||
Padding="0"
|
Padding="0"
|
||||||
@@ -179,9 +98,9 @@
|
|||||||
MenuItemTemplateSelector="{StaticResource NavigationMenuTemplateSelector}"
|
MenuItemTemplateSelector="{StaticResource NavigationMenuTemplateSelector}"
|
||||||
MenuItemsSource="{x:Bind ViewModel.MenuItems, Mode=OneWay}"
|
MenuItemsSource="{x:Bind ViewModel.MenuItems, Mode=OneWay}"
|
||||||
OpenPaneLength="{x:Bind ViewModel.StatePersistenceService.OpenPaneLength, Mode=TwoWay}"
|
OpenPaneLength="{x:Bind ViewModel.StatePersistenceService.OpenPaneLength, Mode=TwoWay}"
|
||||||
|
PaneClosed="NavigationPaneClosed"
|
||||||
PaneDisplayMode="Auto"
|
PaneDisplayMode="Auto"
|
||||||
PaneOpened="NavigationPaneOpened"
|
PaneOpened="NavigationPaneOpened"
|
||||||
PaneClosed="NavigationPaneClosed"
|
|
||||||
Style="{StaticResource CalendarShellNavigationViewStyle}">
|
Style="{StaticResource CalendarShellNavigationViewStyle}">
|
||||||
<muxc:NavigationView.PaneCustomContent>
|
<muxc:NavigationView.PaneCustomContent>
|
||||||
<Grid x:Name="PaneCustomContent" Padding="0,0,0,6">
|
<Grid x:Name="PaneCustomContent" Padding="0,0,0,6">
|
||||||
|
|||||||
@@ -80,18 +80,22 @@
|
|||||||
</TransitionCollection>
|
</TransitionCollection>
|
||||||
</StackPanel.ChildrenTransitions>
|
</StackPanel.ChildrenTransitions>
|
||||||
|
|
||||||
<!-- App About hero card -->
|
<!-- About hero card. -->
|
||||||
<Border
|
<Border
|
||||||
Padding="24,20"
|
Padding="24,20"
|
||||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||||
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
CornerRadius="8">
|
CornerRadius="8">
|
||||||
<Grid ColumnSpacing="16">
|
<Grid ColumnSpacing="16" RowSpacing="16">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<StackPanel
|
<StackPanel
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
@@ -104,8 +108,12 @@
|
|||||||
Source="ms-appx:///Assets/AppEntries/MailAssets/Square150x150Logo.scale-100.png"
|
Source="ms-appx:///Assets/AppEntries/MailAssets/Square150x150Logo.scale-100.png"
|
||||||
Stretch="Uniform" />
|
Stretch="Uniform" />
|
||||||
<StackPanel VerticalAlignment="Center">
|
<StackPanel VerticalAlignment="Center">
|
||||||
<TextBlock Style="{StaticResource TitleTextBlockStyle}" Text="Wino Mail" />
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource TitleTextBlockStyle}"
|
||||||
|
Text="Wino Mail" />
|
||||||
|
<TextBlock
|
||||||
|
VerticalAlignment="Top"
|
||||||
Foreground="{ThemeResource TextFillColorTertiaryBrush}"
|
Foreground="{ThemeResource TextFillColorTertiaryBrush}"
|
||||||
Style="{StaticResource CaptionTextBlockStyle}"
|
Style="{StaticResource CaptionTextBlockStyle}"
|
||||||
Text="{x:Bind ViewModel.VersionText, Mode=OneWay}" />
|
Text="{x:Bind ViewModel.VersionText, Mode=OneWay}" />
|
||||||
@@ -130,6 +138,7 @@
|
|||||||
Stretch="Uniform" />
|
Stretch="Uniform" />
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
Command="{x:Bind ViewModel.NavigateExternalCommand}"
|
Command="{x:Bind ViewModel.NavigateExternalCommand}"
|
||||||
CommandParameter="{x:Bind ViewModel.GitHubUrl, Mode=OneWay}"
|
CommandParameter="{x:Bind ViewModel.GitHubUrl, Mode=OneWay}"
|
||||||
@@ -142,6 +151,7 @@
|
|||||||
Stretch="Uniform" />
|
Stretch="Uniform" />
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
Command="{x:Bind ViewModel.NavigateExternalCommand}"
|
Command="{x:Bind ViewModel.NavigateExternalCommand}"
|
||||||
CommandParameter="Store"
|
CommandParameter="Store"
|
||||||
@@ -157,106 +167,6 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<!-- Loading indicator -->
|
|
||||||
<ProgressRing
|
|
||||||
x:Name="WinoAccountBusyRing"
|
|
||||||
Width="24"
|
|
||||||
Height="24"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
x:Load="{x:Bind ViewModel.IsWinoAccountBusy, Mode=OneWay}"
|
|
||||||
IsActive="True" />
|
|
||||||
|
|
||||||
<!-- Wino Account: Signed-out state -->
|
|
||||||
<controls:SettingsCard
|
|
||||||
x:Name="SignedOutCard"
|
|
||||||
Description="{x:Bind domain:Translator.SettingsHome_WinoAccount_SignedOutDescription}"
|
|
||||||
Header="{x:Bind domain:Translator.SettingsHome_WinoAccount_Title}"
|
|
||||||
x:Load="{x:Bind ViewModel.IsWinoAccountSignedOut, Mode=OneWay}">
|
|
||||||
<controls:SettingsCard.HeaderIcon>
|
|
||||||
<FontIcon Glyph="" />
|
|
||||||
</controls:SettingsCard.HeaderIcon>
|
|
||||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
|
||||||
<Button
|
|
||||||
Command="{x:Bind ViewModel.WinoAccountSignInCommand}"
|
|
||||||
Content="{x:Bind domain:Translator.Buttons_SignIn}"
|
|
||||||
Style="{StaticResource AccentButtonStyle}" />
|
|
||||||
<Button Command="{x:Bind ViewModel.WinoAccountRegisterCommand}" Content="{x:Bind domain:Translator.Buttons_CreateAccount}" />
|
|
||||||
</StackPanel>
|
|
||||||
</controls:SettingsCard>
|
|
||||||
|
|
||||||
<!-- Wino Account: Signed-in state -->
|
|
||||||
<controls:SettingsExpander
|
|
||||||
x:Name="SignedInExpander"
|
|
||||||
Description="{x:Bind ViewModel.WinoAccountStatusText, Mode=OneWay}"
|
|
||||||
Header="{x:Bind ViewModel.WinoAccountEmail, Mode=OneWay}"
|
|
||||||
x:Load="{x:Bind ViewModel.IsWinoAccountSignedIn, Mode=OneWay}">
|
|
||||||
<controls:SettingsExpander.HeaderIcon>
|
|
||||||
<FontIcon Glyph="" />
|
|
||||||
</controls:SettingsExpander.HeaderIcon>
|
|
||||||
<Button
|
|
||||||
Command="{x:Bind ViewModel.WinoAccountSignOutCommand}"
|
|
||||||
Content="{x:Bind domain:Translator.WinoAccount_SignOutButton_Action}" />
|
|
||||||
|
|
||||||
<controls:SettingsExpander.Items>
|
|
||||||
<!-- AI Pack active (with progress bar) -->
|
|
||||||
<controls:SettingsCard
|
|
||||||
x:Name="AiPackActiveCard"
|
|
||||||
Description="{x:Bind ViewModel.AiUsageSummary, Mode=OneWay}"
|
|
||||||
Header="{x:Bind domain:Translator.SettingsHome_AiPack_Title}"
|
|
||||||
x:Load="{x:Bind ViewModel.CanShowAiUsage, Mode=OneWay}">
|
|
||||||
<controls:SettingsCard.HeaderIcon>
|
|
||||||
<ImageIcon Source="ms-appx:///Assets/AIPackIcon.png" />
|
|
||||||
</controls:SettingsCard.HeaderIcon>
|
|
||||||
<StackPanel MinWidth="200" Spacing="4">
|
|
||||||
<ProgressBar
|
|
||||||
Height="8"
|
|
||||||
Maximum="100"
|
|
||||||
Value="{x:Bind ViewModel.AiUsagePercent, Mode=OneWay}" />
|
|
||||||
<TextBlock
|
|
||||||
Foreground="{ThemeResource TextFillColorTertiaryBrush}"
|
|
||||||
Style="{StaticResource CaptionTextBlockStyle}"
|
|
||||||
Text="{x:Bind ViewModel.AiBillingPeriodSummary, Mode=OneWay}" />
|
|
||||||
</StackPanel>
|
|
||||||
</controls:SettingsCard>
|
|
||||||
|
|
||||||
<!-- AI Pack not purchased -->
|
|
||||||
<controls:SettingsCard
|
|
||||||
x:Name="AiPackBuyCard"
|
|
||||||
Description="{x:Bind domain:Translator.WinoAccount_Management_AiPackBuyDescription}"
|
|
||||||
Header="{x:Bind domain:Translator.SettingsHome_AiPack_Title}"
|
|
||||||
x:Load="{x:Bind ViewModel.CanShowBuyAiPack, Mode=OneWay}">
|
|
||||||
<controls:SettingsCard.HeaderIcon>
|
|
||||||
<ImageIcon Source="ms-appx:///Assets/AIPackIcon.png" />
|
|
||||||
</controls:SettingsCard.HeaderIcon>
|
|
||||||
<Button
|
|
||||||
Command="{x:Bind ViewModel.OpenBuyAiPackPageCommand}"
|
|
||||||
Content="{x:Bind domain:Translator.Buttons_Purchase}"
|
|
||||||
Style="{StaticResource AccentButtonStyle}" />
|
|
||||||
</controls:SettingsCard>
|
|
||||||
|
|
||||||
<!-- Settings sync -->
|
|
||||||
<controls:SettingsCard
|
|
||||||
Click="WinoAccountManagementClicked"
|
|
||||||
Description="{x:Bind domain:Translator.SettingsHome_SettingsSync_Description}"
|
|
||||||
Header="{x:Bind domain:Translator.SettingsHome_SettingsSync_Title}"
|
|
||||||
IsClickEnabled="True">
|
|
||||||
<controls:SettingsCard.HeaderIcon>
|
|
||||||
<FontIcon Glyph="" />
|
|
||||||
</controls:SettingsCard.HeaderIcon>
|
|
||||||
</controls:SettingsCard>
|
|
||||||
|
|
||||||
<!-- Manage Wino Account -->
|
|
||||||
<controls:SettingsCard
|
|
||||||
Click="WinoAccountManagementClicked"
|
|
||||||
Header="{x:Bind domain:Translator.SettingsHome_WinoAccount_ManageLink}"
|
|
||||||
IsClickEnabled="True">
|
|
||||||
<controls:SettingsCard.HeaderIcon>
|
|
||||||
<FontIcon Glyph="" />
|
|
||||||
</controls:SettingsCard.HeaderIcon>
|
|
||||||
</controls:SettingsCard>
|
|
||||||
</controls:SettingsExpander.Items>
|
|
||||||
</controls:SettingsExpander>
|
|
||||||
|
|
||||||
|
|
||||||
<Border
|
<Border
|
||||||
Padding="12,0,34,20"
|
Padding="12,0,34,20"
|
||||||
|
|||||||
@@ -523,10 +523,10 @@
|
|||||||
ItemInvoked="NavigationViewItemInvoked"
|
ItemInvoked="NavigationViewItemInvoked"
|
||||||
MenuItemTemplateSelector="{StaticResource NavigationMenuTemplateSelector}"
|
MenuItemTemplateSelector="{StaticResource NavigationMenuTemplateSelector}"
|
||||||
OpenPaneLength="{x:Bind ViewModel.StatePersistenceService.OpenPaneLength, Mode=TwoWay}"
|
OpenPaneLength="{x:Bind ViewModel.StatePersistenceService.OpenPaneLength, Mode=TwoWay}"
|
||||||
PaneDisplayMode="Auto"
|
|
||||||
PaneOpening="NavigationPaneOpening"
|
|
||||||
PaneOpened="NavigationPaneOpened"
|
|
||||||
PaneClosed="NavigationPaneClosed"
|
PaneClosed="NavigationPaneClosed"
|
||||||
|
PaneDisplayMode="Auto"
|
||||||
|
PaneOpened="NavigationPaneOpened"
|
||||||
|
PaneOpening="NavigationPaneOpening"
|
||||||
ScrollViewer.VerticalScrollBarVisibility="Hidden"
|
ScrollViewer.VerticalScrollBarVisibility="Hidden"
|
||||||
SelectionChanged="MenuSelectionChanged"
|
SelectionChanged="MenuSelectionChanged"
|
||||||
Style="{StaticResource CalendarShellNavigationViewStyle}">
|
Style="{StaticResource CalendarShellNavigationViewStyle}">
|
||||||
|
|||||||
Reference in New Issue
Block a user