Live store update notifications.
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -67,6 +67,9 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
|||||||
|
|
||||||
public bool IsVerticalCalendar => StatePersistenceService.CalendarDisplayType == CalendarDisplayType.Month;
|
public bool IsVerticalCalendar => StatePersistenceService.CalendarDisplayType == CalendarDisplayType.Month;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool isStoreUpdateItemVisible;
|
||||||
|
|
||||||
// For updating account calendars asynchronously.
|
// For updating account calendars asynchronously.
|
||||||
private SemaphoreSlim _accountCalendarUpdateSemaphoreSlim = new(1);
|
private SemaphoreSlim _accountCalendarUpdateSemaphoreSlim = new(1);
|
||||||
|
|
||||||
@@ -77,12 +80,14 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
|||||||
IAccountCalendarStateService accountCalendarStateService,
|
IAccountCalendarStateService accountCalendarStateService,
|
||||||
INavigationService navigationService,
|
INavigationService navigationService,
|
||||||
IMailDialogService dialogService,
|
IMailDialogService dialogService,
|
||||||
IUpdateManager updateManager)
|
IUpdateManager updateManager,
|
||||||
|
IStoreUpdateService storeUpdateService)
|
||||||
{
|
{
|
||||||
_accountService = accountService;
|
_accountService = accountService;
|
||||||
_calendarService = calendarService;
|
_calendarService = calendarService;
|
||||||
_dialogService = dialogService;
|
_dialogService = dialogService;
|
||||||
_updateManager = updateManager;
|
_updateManager = updateManager;
|
||||||
|
_storeUpdateService = storeUpdateService;
|
||||||
|
|
||||||
AccountCalendarStateService = accountCalendarStateService;
|
AccountCalendarStateService = accountCalendarStateService;
|
||||||
AccountCalendarStateService.AccountCalendarSelectionStateChanged += UpdateAccountCalendarRequested;
|
AccountCalendarStateService.AccountCalendarSelectionStateChanged += UpdateAccountCalendarRequested;
|
||||||
@@ -100,6 +105,7 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
|||||||
base.OnDispatcherAssigned();
|
base.OnDispatcherAssigned();
|
||||||
|
|
||||||
AccountCalendarStateService.Dispatcher = Dispatcher;
|
AccountCalendarStateService.Dispatcher = Dispatcher;
|
||||||
|
_ = RefreshFooterItemsAsync(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrefefencesChanged(object sender, string e)
|
private void PrefefencesChanged(object sender, string e)
|
||||||
@@ -115,10 +121,23 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void PreferencesServiceChanged(object sender, string e)
|
||||||
|
{
|
||||||
|
if (e == nameof(IPreferencesService.IsStoreUpdateNotificationsEnabled))
|
||||||
|
{
|
||||||
|
await RefreshFooterItemsAsync(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override async void OnNavigatedTo(NavigationMode mode, object parameters)
|
public override async void OnNavigatedTo(NavigationMode mode, object parameters)
|
||||||
{
|
{
|
||||||
base.OnNavigatedTo(mode, parameters);
|
base.OnNavigatedTo(mode, parameters);
|
||||||
|
|
||||||
|
PreferencesService.PreferenceChanged -= PreferencesServiceChanged;
|
||||||
|
PreferencesService.PreferenceChanged += PreferencesServiceChanged;
|
||||||
|
|
||||||
|
await RefreshFooterItemsAsync(mode == NavigationMode.New);
|
||||||
|
|
||||||
// Preserve the existing calendar shell frame state when the user switches
|
// Preserve the existing calendar shell frame state when the user switches
|
||||||
// between Mail and Calendar modes. Back/forward restoration should not
|
// between Mail and Calendar modes. Back/forward restoration should not
|
||||||
// force a new CalendarPage navigation, otherwise pages like
|
// force a new CalendarPage navigation, otherwise pages like
|
||||||
@@ -141,6 +160,13 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
|||||||
TodayClicked();
|
TodayClicked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void OnNavigatedFrom(NavigationMode mode, object parameters)
|
||||||
|
{
|
||||||
|
base.OnNavigatedFrom(mode, parameters);
|
||||||
|
|
||||||
|
PreferencesService.PreferenceChanged -= PreferencesServiceChanged;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ShowWhatIsNewIfNeededAsync()
|
private async Task ShowWhatIsNewIfNeededAsync()
|
||||||
{
|
{
|
||||||
if (!_updateManager.ShouldShowUpdateNotes())
|
if (!_updateManager.ShouldShowUpdateNotes())
|
||||||
@@ -154,6 +180,22 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
|||||||
await _dialogService.ShowWhatIsNewDialogAsync(notes);
|
await _dialogService.ShowWhatIsNewDialogAsync(notes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task RefreshFooterItemsAsync(bool showNotification)
|
||||||
|
{
|
||||||
|
await _storeUpdateService.RefreshAvailabilityAsync(showNotification).ConfigureAwait(false);
|
||||||
|
|
||||||
|
await ExecuteUIThread(() =>
|
||||||
|
{
|
||||||
|
IsStoreUpdateItemVisible = _storeUpdateService.HasAvailableUpdate && PreferencesService.IsStoreUpdateNotificationsEnabled;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task StartStoreUpdateAsync()
|
||||||
|
{
|
||||||
|
await _storeUpdateService.StartUpdateAsync().ConfigureAwait(false);
|
||||||
|
await RefreshFooterItemsAsync(false).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
private async void AccountCalendarStateCollectivelyChanged(object sender, GroupedAccountCalendarViewModel e)
|
private async void AccountCalendarStateCollectivelyChanged(object sender, GroupedAccountCalendarViewModel e)
|
||||||
{
|
{
|
||||||
// When using three-state checkbox, multiple accounts will be selected/unselected at the same time.
|
// When using three-state checkbox, multiple accounts will be selected/unselected at the same time.
|
||||||
@@ -211,40 +253,34 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
|||||||
|
|
||||||
private void ForceNavigateCalendarDate()
|
private void ForceNavigateCalendarDate()
|
||||||
{
|
{
|
||||||
if (SelectedMenuItemIndex == -1)
|
var args = new CalendarPageNavigationArgs()
|
||||||
{
|
{
|
||||||
var args = new CalendarPageNavigationArgs()
|
NavigationDate = _navigationDate ?? DateTime.Now.Date
|
||||||
{
|
};
|
||||||
NavigationDate = _navigationDate ?? DateTime.Now.Date
|
|
||||||
};
|
|
||||||
|
|
||||||
// Already on calendar. Just navigate.
|
NavigationService.Navigate(WinoPage.CalendarPage, args);
|
||||||
NavigationService.Navigate(WinoPage.CalendarPage, args);
|
_navigationDate = null;
|
||||||
|
|
||||||
_navigationDate = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SelectedMenuItemIndex = -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void OnSelectedMenuItemIndexChanged(int oldValue, int newValue)
|
partial void OnSelectedMenuItemIndexChanged(int oldValue, int newValue)
|
||||||
{
|
{
|
||||||
switch (newValue)
|
if (newValue < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (newValue == 0)
|
||||||
{
|
{
|
||||||
case -1:
|
NavigationService.Navigate(WinoPage.ManageAccountsPage);
|
||||||
ForceNavigateCalendarDate();
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
NavigationService.Navigate(WinoPage.ManageAccountsPage);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
NavigationService.Navigate(WinoPage.SettingsPage);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
else if (newValue == 1)
|
||||||
|
{
|
||||||
|
NavigationService.Navigate(WinoPage.SettingsPage);
|
||||||
|
}
|
||||||
|
else if (IsStoreUpdateItemVisible && newValue == 2)
|
||||||
|
{
|
||||||
|
_ = StartStoreUpdateAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedMenuItemIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
@@ -301,6 +337,7 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
|||||||
private readonly ICalendarService _calendarService;
|
private readonly ICalendarService _calendarService;
|
||||||
private readonly IMailDialogService _dialogService;
|
private readonly IMailDialogService _dialogService;
|
||||||
private readonly IUpdateManager _updateManager;
|
private readonly IUpdateManager _updateManager;
|
||||||
|
private readonly IStoreUpdateService _storeUpdateService;
|
||||||
|
|
||||||
#region Commands
|
#region Commands
|
||||||
|
|
||||||
@@ -476,7 +513,7 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
|||||||
public async void Receive(CalendarEnableStatusChangedMessage message)
|
public async void Receive(CalendarEnableStatusChangedMessage message)
|
||||||
=> await ExecuteUIThread(() => IsCalendarEnabled = message.IsEnabled);
|
=> await ExecuteUIThread(() => IsCalendarEnabled = message.IsEnabled);
|
||||||
|
|
||||||
public void Receive(NavigateManageAccountsRequested message) => SelectedMenuItemIndex = 1;
|
public void Receive(NavigateManageAccountsRequested message) => SelectedMenuItemIndex = 0;
|
||||||
|
|
||||||
public void Receive(CalendarDisplayTypeChangedMessage message)
|
public void Receive(CalendarDisplayTypeChangedMessage message)
|
||||||
{
|
{
|
||||||
@@ -539,3 +576,12 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
|||||||
return (startDate, startDate.AddMinutes(30));
|
return (startDate, startDate.AddMinutes(30));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Wino.Core.Domain;
|
namespace Wino.Core.Domain;
|
||||||
|
|
||||||
public static class Constants
|
public static class Constants
|
||||||
{
|
{
|
||||||
@@ -21,6 +21,8 @@ public static class Constants
|
|||||||
public const string ToastModeKey = nameof(ToastModeKey);
|
public const string ToastModeKey = nameof(ToastModeKey);
|
||||||
public const string ToastModeMail = nameof(ToastModeMail);
|
public const string ToastModeMail = nameof(ToastModeMail);
|
||||||
public const string ToastModeCalendar = nameof(ToastModeCalendar);
|
public const string ToastModeCalendar = nameof(ToastModeCalendar);
|
||||||
|
public const string ToastStoreUpdateActionKey = nameof(ToastStoreUpdateActionKey);
|
||||||
|
public const string ToastStoreUpdateActionInstall = nameof(ToastStoreUpdateActionInstall);
|
||||||
public const string ClientLogFile = "Client_.log";
|
public const string ClientLogFile = "Client_.log";
|
||||||
public const string ServerLogFile = "Server_.log";
|
public const string ServerLogFile = "Server_.log";
|
||||||
public const string LogArchiveFileName = "WinoLogs.zip";
|
public const string LogArchiveFileName = "WinoLogs.zip";
|
||||||
@@ -28,3 +30,4 @@ public static class Constants
|
|||||||
public const string WinoMailIdentiifer = nameof(WinoMailIdentiifer);
|
public const string WinoMailIdentiifer = nameof(WinoMailIdentiifer);
|
||||||
public const string WinoCalendarIdentifier = nameof(WinoCalendarIdentifier);
|
public const string WinoCalendarIdentifier = nameof(WinoCalendarIdentifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,14 @@ public interface INotificationBuilder
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
void CreateWebView2RuntimeMissingNotification();
|
void CreateWebView2RuntimeMissingNotification();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shows a notification when a Microsoft Store update is available.
|
||||||
|
/// </summary>
|
||||||
|
void CreateStoreUpdateNotification();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a calendar reminder toast for the specified calendar item.
|
/// Creates a calendar reminder toast for the specified calendar item.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Task CreateCalendarReminderNotificationAsync(CalendarItem calendarItem, long reminderDurationInSeconds);
|
Task CreateCalendarReminderNotificationAsync(CalendarItem calendarItem, long reminderDurationInSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.ComponentModel;
|
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;
|
||||||
@@ -57,6 +57,11 @@ public interface IPreferencesService : INotifyPropertyChanged
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
WinoApplicationMode DefaultApplicationMode { get; set; }
|
WinoApplicationMode DefaultApplicationMode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Setting: Whether Microsoft Store update notifications should be shown.
|
||||||
|
/// </summary>
|
||||||
|
bool IsStoreUpdateNotificationsEnabled { get; set; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Mail
|
#region Mail
|
||||||
@@ -241,3 +246,4 @@ public interface IPreferencesService : INotifyPropertyChanged
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Wino.Core.Domain.Interfaces;
|
||||||
|
|
||||||
|
public interface IStoreUpdateService
|
||||||
|
{
|
||||||
|
bool HasAvailableUpdate { get; }
|
||||||
|
|
||||||
|
Task<bool> RefreshAvailabilityAsync(bool showNotification = false);
|
||||||
|
|
||||||
|
Task<bool> StartUpdateAsync();
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
namespace Wino.Core.Domain.MenuItems;
|
||||||
|
|
||||||
|
public class StoreUpdateMenuItem : MenuItemBase { }
|
||||||
@@ -599,6 +599,7 @@
|
|||||||
"MenuNewMail": "New Mail",
|
"MenuNewMail": "New Mail",
|
||||||
"MenuRate": "Rate Wino",
|
"MenuRate": "Rate Wino",
|
||||||
"MenuSettings": "Settings",
|
"MenuSettings": "Settings",
|
||||||
|
"MenuUpdateAvailable": "Update Available",
|
||||||
"MergedAccountCommonFolderArchive": "Archive",
|
"MergedAccountCommonFolderArchive": "Archive",
|
||||||
"MergedAccountCommonFolderDraft": "Draft",
|
"MergedAccountCommonFolderDraft": "Draft",
|
||||||
"MergedAccountCommonFolderInbox": "Inbox",
|
"MergedAccountCommonFolderInbox": "Inbox",
|
||||||
@@ -622,6 +623,8 @@
|
|||||||
"Notifications_MultipleNotificationsTitle": "New Mail",
|
"Notifications_MultipleNotificationsTitle": "New Mail",
|
||||||
"Notifications_WinoUpdatedMessage": "Checkout new version {0}",
|
"Notifications_WinoUpdatedMessage": "Checkout new version {0}",
|
||||||
"Notifications_WinoUpdatedTitle": "Wino Mail has been updated.",
|
"Notifications_WinoUpdatedTitle": "Wino Mail has been updated.",
|
||||||
|
"Notifications_StoreUpdateAvailableTitle": "Update available",
|
||||||
|
"Notifications_StoreUpdateAvailableMessage": "A newer version of Wino Mail is ready to install from Microsoft Store.",
|
||||||
"OnlineSearchFailed_Message": "Failed to perform search\n{0}\n\nListing offline mails.",
|
"OnlineSearchFailed_Message": "Failed to perform search\n{0}\n\nListing offline mails.",
|
||||||
"OnlineSearchTry_Line1": "Can't find what you are looking for?",
|
"OnlineSearchTry_Line1": "Can't find what you are looking for?",
|
||||||
"OnlineSearchTry_Line2": "Try online search.",
|
"OnlineSearchTry_Line2": "Try online search.",
|
||||||
@@ -700,6 +703,8 @@
|
|||||||
"SettingsAppPreferences_StartupBehavior_FatalError": "Fatal error occurred while changing the startup mode for Wino Mail.",
|
"SettingsAppPreferences_StartupBehavior_FatalError": "Fatal error occurred while changing the startup mode for Wino Mail.",
|
||||||
"SettingsAppPreferences_StartupBehavior_Title": "Start minimized on Windows startup",
|
"SettingsAppPreferences_StartupBehavior_Title": "Start minimized on Windows startup",
|
||||||
"SettingsAppPreferences_Title": "App Preferences",
|
"SettingsAppPreferences_Title": "App Preferences",
|
||||||
|
"SettingsAppPreferences_StoreUpdateNotifications_Title": "Store update notifications",
|
||||||
|
"SettingsAppPreferences_StoreUpdateNotifications_Description": "Show notifications and footer actions when a Microsoft Store update is available.",
|
||||||
"SettingsAutoSelectNextItem_Description": "Select the next item after you delete or move a mail.",
|
"SettingsAutoSelectNextItem_Description": "Select the next item after you delete or move a mail.",
|
||||||
"SettingsAutoSelectNextItem_Title": "Auto select next item",
|
"SettingsAutoSelectNextItem_Title": "Auto select next item",
|
||||||
"SettingsAvailableThemes_Description": "Select a theme from Wino's own collection for your taste or apply your own themes.",
|
"SettingsAvailableThemes_Description": "Select a theme from Wino's own collection for your taste or apply your own themes.",
|
||||||
@@ -1117,3 +1122,5 @@
|
|||||||
"AccountSetup_TryAgainButton": "Try Again",
|
"AccountSetup_TryAgainButton": "Try Again",
|
||||||
"ImapCalDavSettings_AutoDiscoveryFailed": "Auto-discovery failed. Please enter settings manually in the Advanced tab."
|
"ImapCalDavSettings_AutoDiscoveryFailed": "Auto-discovery failed. Please enter settings manually in the Advanced tab."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -55,6 +55,7 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
private readonly SettingsItem SettingsItem = new SettingsItem();
|
private readonly SettingsItem SettingsItem = new SettingsItem();
|
||||||
private readonly ManageAccountsMenuItem ManageAccountsMenuItem = new ManageAccountsMenuItem();
|
private readonly ManageAccountsMenuItem ManageAccountsMenuItem = new ManageAccountsMenuItem();
|
||||||
private readonly ContactsMenuItem ContactsMenuItem = new ContactsMenuItem();
|
private readonly ContactsMenuItem ContactsMenuItem = new ContactsMenuItem();
|
||||||
|
private readonly StoreUpdateMenuItem StoreUpdateMenuItem = new StoreUpdateMenuItem();
|
||||||
|
|
||||||
public IMenuItem CreateMailMenuItem = new NewMailMenuItem();
|
public IMenuItem CreateMailMenuItem = new NewMailMenuItem();
|
||||||
|
|
||||||
@@ -79,6 +80,7 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
private readonly IMimeFileService _mimeFileService;
|
private readonly IMimeFileService _mimeFileService;
|
||||||
private readonly IWebView2RuntimeValidatorService _webView2RuntimeValidatorService;
|
private readonly IWebView2RuntimeValidatorService _webView2RuntimeValidatorService;
|
||||||
private readonly IUpdateManager _updateManager;
|
private readonly IUpdateManager _updateManager;
|
||||||
|
private readonly IStoreUpdateService _storeUpdateService;
|
||||||
|
|
||||||
private readonly INativeAppService _nativeAppService;
|
private readonly INativeAppService _nativeAppService;
|
||||||
private readonly IMailService _mailService;
|
private readonly IMailService _mailService;
|
||||||
@@ -102,7 +104,8 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
IConfigurationService configurationService,
|
IConfigurationService configurationService,
|
||||||
IStartupBehaviorService startupBehaviorService,
|
IStartupBehaviorService startupBehaviorService,
|
||||||
IWebView2RuntimeValidatorService webView2RuntimeValidatorService,
|
IWebView2RuntimeValidatorService webView2RuntimeValidatorService,
|
||||||
IUpdateManager updateManager)
|
IUpdateManager updateManager,
|
||||||
|
IStoreUpdateService storeUpdateService)
|
||||||
{
|
{
|
||||||
StatePersistenceService = statePersistanceService;
|
StatePersistenceService = statePersistanceService;
|
||||||
|
|
||||||
@@ -124,6 +127,7 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
_winoRequestDelegator = winoRequestDelegator;
|
_winoRequestDelegator = winoRequestDelegator;
|
||||||
_webView2RuntimeValidatorService = webView2RuntimeValidatorService;
|
_webView2RuntimeValidatorService = webView2RuntimeValidatorService;
|
||||||
_updateManager = updateManager;
|
_updateManager = updateManager;
|
||||||
|
_storeUpdateService = storeUpdateService;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDispatcherAssigned()
|
protected override void OnDispatcherAssigned()
|
||||||
@@ -142,8 +146,10 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
return _contextMenuItemService.GetFolderContextMenuActions(folder);
|
return _contextMenuItemService.GetFolderContextMenuActions(folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task CreateFooterItemsAsync()
|
private async Task CreateFooterItemsAsync(bool showNotification = false)
|
||||||
{
|
{
|
||||||
|
await _storeUpdateService.RefreshAvailabilityAsync(showNotification).ConfigureAwait(false);
|
||||||
|
|
||||||
await ExecuteUIThread(() =>
|
await ExecuteUIThread(() =>
|
||||||
{
|
{
|
||||||
// TODO: Selected footer item container still remains selected after re-creation.
|
// TODO: Selected footer item container still remains selected after re-creation.
|
||||||
@@ -159,6 +165,12 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
|
|
||||||
FooterItems.Add(ContactsMenuItem);
|
FooterItems.Add(ContactsMenuItem);
|
||||||
FooterItems.Add(ManageAccountsMenuItem);
|
FooterItems.Add(ManageAccountsMenuItem);
|
||||||
|
|
||||||
|
if (_storeUpdateService.HasAvailableUpdate && PreferencesService.IsStoreUpdateNotificationsEnabled)
|
||||||
|
{
|
||||||
|
FooterItems.Add(StoreUpdateMenuItem);
|
||||||
|
}
|
||||||
|
|
||||||
FooterItems.Add(SettingsItem);
|
FooterItems.Add(SettingsItem);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -223,10 +235,21 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void PreferencesServiceChanged(object sender, string e)
|
||||||
|
{
|
||||||
|
if (e == nameof(IPreferencesService.IsStoreUpdateNotificationsEnabled))
|
||||||
|
{
|
||||||
|
await CreateFooterItemsAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override async void OnNavigatedTo(NavigationMode mode, object parameters)
|
public override async void OnNavigatedTo(NavigationMode mode, object parameters)
|
||||||
{
|
{
|
||||||
base.OnNavigatedTo(mode, parameters);
|
base.OnNavigatedTo(mode, parameters);
|
||||||
|
|
||||||
|
PreferencesService.PreferenceChanged -= PreferencesServiceChanged;
|
||||||
|
PreferencesService.PreferenceChanged += PreferencesServiceChanged;
|
||||||
|
|
||||||
if (mode == NavigationMode.Back)
|
if (mode == NavigationMode.Back)
|
||||||
{
|
{
|
||||||
// Preserve current mail/folder selection and active rendering page when
|
// Preserve current mail/folder selection and active rendering page when
|
||||||
@@ -243,7 +266,7 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await CreateFooterItemsAsync();
|
await CreateFooterItemsAsync(true);
|
||||||
|
|
||||||
await RecreateMenuItemsAsync();
|
await RecreateMenuItemsAsync();
|
||||||
await ProcessLaunchOptionsAsync();
|
await ProcessLaunchOptionsAsync();
|
||||||
@@ -268,6 +291,13 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void OnNavigatedFrom(NavigationMode mode, object parameters)
|
||||||
|
{
|
||||||
|
base.OnNavigatedFrom(mode, parameters);
|
||||||
|
|
||||||
|
PreferencesService.PreferenceChanged -= PreferencesServiceChanged;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ShowWhatIsNewIfNeededAsync()
|
private async Task ShowWhatIsNewIfNeededAsync()
|
||||||
{
|
{
|
||||||
if (!_updateManager.ShouldShowUpdateNotes())
|
if (!_updateManager.ShouldShowUpdateNotes())
|
||||||
@@ -638,6 +668,11 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
// Don't navigate to merged account if it's already selected. Preserve user's already selected folder.
|
// Don't navigate to merged account if it's already selected. Preserve user's already selected folder.
|
||||||
await ChangeLoadedAccountAsync(clickedMergedAccountMenuItem, true);
|
await ChangeLoadedAccountAsync(clickedMergedAccountMenuItem, true);
|
||||||
}
|
}
|
||||||
|
else if (clickedMenuItem is StoreUpdateMenuItem)
|
||||||
|
{
|
||||||
|
await _storeUpdateService.StartUpdateAsync().ConfigureAwait(false);
|
||||||
|
await CreateFooterItemsAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
else if (clickedMenuItem is SettingsItem)
|
else if (clickedMenuItem is SettingsItem)
|
||||||
{
|
{
|
||||||
NavigationService.Navigate(WinoPage.SettingsPage, parameter, NavigationReferenceFrame.InnerShellFrame, NavigationTransitionType.None);
|
NavigationService.Navigate(WinoPage.SettingsPage, parameter, NavigationReferenceFrame.InnerShellFrame, NavigationTransitionType.None);
|
||||||
@@ -1051,7 +1086,7 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
|
|
||||||
public async void Receive(LanguageChanged message)
|
public async void Receive(LanguageChanged message)
|
||||||
{
|
{
|
||||||
await CreateFooterItemsAsync();
|
await CreateFooterItemsAsync(true);
|
||||||
await RecreateMenuItemsAsync();
|
await RecreateMenuItemsAsync();
|
||||||
await RestoreSelectedAccountAfterMenuRefreshAsync(false);
|
await RestoreSelectedAccountAfterMenuRefreshAsync(false);
|
||||||
}
|
}
|
||||||
@@ -1245,3 +1280,10 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -296,6 +296,13 @@ public partial class App : WinoApplication,
|
|||||||
{
|
{
|
||||||
var toastArguments = ToastArguments.Parse(toastArgs.Argument);
|
var toastArguments = ToastArguments.Parse(toastArgs.Argument);
|
||||||
|
|
||||||
|
if (toastArguments.TryGetValue(Constants.ToastStoreUpdateActionKey, out string storeUpdateAction) &&
|
||||||
|
storeUpdateAction == Constants.ToastStoreUpdateActionInstall)
|
||||||
|
{
|
||||||
|
await HandleStoreUpdateToastAsync();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Check calendar reminder toast activation first.
|
// Check calendar reminder toast activation first.
|
||||||
if (toastArguments.TryGetValue(Constants.ToastCalendarActionKey, out string calendarAction) &&
|
if (toastArguments.TryGetValue(Constants.ToastCalendarActionKey, out string calendarAction) &&
|
||||||
toastArguments.TryGetValue(Constants.ToastCalendarItemIdKey, out string calendarItemIdString) &&
|
toastArguments.TryGetValue(Constants.ToastCalendarItemIdKey, out string calendarItemIdString) &&
|
||||||
@@ -333,6 +340,21 @@ public partial class App : WinoApplication,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task HandleStoreUpdateToastAsync()
|
||||||
|
{
|
||||||
|
if (!IsAppRunning())
|
||||||
|
{
|
||||||
|
await CreateAndActivateWindow(null!);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EnsureMainWindowVisibleAndForeground();
|
||||||
|
}
|
||||||
|
|
||||||
|
var storeUpdateService = Services.GetRequiredService<IStoreUpdateService>();
|
||||||
|
await storeUpdateService.StartUpdateAsync();
|
||||||
|
}
|
||||||
|
|
||||||
private async Task HandleCalendarToastNavigationAsync(Guid calendarItemId)
|
private async Task HandleCalendarToastNavigationAsync(Guid calendarItemId)
|
||||||
{
|
{
|
||||||
var calendarService = Services.GetRequiredService<ICalendarService>();
|
var calendarService = Services.GetRequiredService<ICalendarService>();
|
||||||
@@ -997,3 +1019,5 @@ public partial class App : WinoApplication,
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ public static class CoreUWPContainerSetup
|
|||||||
services.AddTransient<IConfigurationService, ConfigurationService>();
|
services.AddTransient<IConfigurationService, ConfigurationService>();
|
||||||
services.AddTransient<IFileService, FileService>();
|
services.AddTransient<IFileService, FileService>();
|
||||||
services.AddTransient<IStoreRatingService, StoreRatingService>();
|
services.AddTransient<IStoreRatingService, StoreRatingService>();
|
||||||
|
services.AddSingleton<IStoreUpdateService, StoreUpdateService>();
|
||||||
services.AddTransient<IKeyPressService, KeyPressService>();
|
services.AddTransient<IKeyPressService, KeyPressService>();
|
||||||
services.AddTransient<IWebView2RuntimeValidatorService, WebView2RuntimeValidatorService>();
|
services.AddTransient<IWebView2RuntimeValidatorService, WebView2RuntimeValidatorService>();
|
||||||
services.AddTransient<INotificationBuilder, NotificationBuilder>();
|
services.AddTransient<INotificationBuilder, NotificationBuilder>();
|
||||||
@@ -53,3 +54,5 @@ public static class CoreUWPContainerSetup
|
|||||||
services.AddTransient(typeof(KeyboardShortcutsPageViewModel));
|
services.AddTransient(typeof(KeyboardShortcutsPageViewModel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -387,7 +387,8 @@
|
|||||||
NewMailTemplate="{StaticResource CreateNewMailTemplate}"
|
NewMailTemplate="{StaticResource CreateNewMailTemplate}"
|
||||||
RatingItemTemplate="{StaticResource RatingItemTemplate}"
|
RatingItemTemplate="{StaticResource RatingItemTemplate}"
|
||||||
SeperatorTemplate="{StaticResource SeperatorTemplate}"
|
SeperatorTemplate="{StaticResource SeperatorTemplate}"
|
||||||
SettingsItemTemplate="{StaticResource SettingsItemTemplate}" />
|
SettingsItemTemplate="{StaticResource SettingsItemTemplate}"
|
||||||
|
StoreUpdateItemTemplate="{StaticResource StoreUpdateItemTemplate}" />
|
||||||
</Page.Resources>
|
</Page.Resources>
|
||||||
|
|
||||||
<Grid
|
<Grid
|
||||||
@@ -477,3 +478,5 @@
|
|||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</abstract:MailAppShellAbstract>
|
</abstract:MailAppShellAbstract>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ public partial class NavigationMenuTemplateSelector : DataTemplateSelector
|
|||||||
public DataTemplate MergedAccountMoreExpansionItemTemplate { get; set; } = null!;
|
public DataTemplate MergedAccountMoreExpansionItemTemplate { get; set; } = null!;
|
||||||
public DataTemplate FolderMenuTemplate { get; set; } = null!;
|
public DataTemplate FolderMenuTemplate { get; set; } = null!;
|
||||||
public DataTemplate SettingsItemTemplate { get; set; } = null!;
|
public DataTemplate SettingsItemTemplate { get; set; } = null!;
|
||||||
|
public DataTemplate StoreUpdateItemTemplate { get; set; } = null!;
|
||||||
public DataTemplate MoreItemsFolderTemplate { get; set; } = null!;
|
public DataTemplate MoreItemsFolderTemplate { get; set; } = null!;
|
||||||
public DataTemplate RatingItemTemplate { get; set; } = null!;
|
public DataTemplate RatingItemTemplate { get; set; } = null!;
|
||||||
public DataTemplate CreateNewFolderTemplate { get; set; } = null!;
|
public DataTemplate CreateNewFolderTemplate { get; set; } = null!;
|
||||||
@@ -32,6 +33,8 @@ public partial class NavigationMenuTemplateSelector : DataTemplateSelector
|
|||||||
return ContactsMenuItemTemplate;
|
return ContactsMenuItemTemplate;
|
||||||
else if (item is SettingsItem)
|
else if (item is SettingsItem)
|
||||||
return SettingsItemTemplate;
|
return SettingsItemTemplate;
|
||||||
|
else if (item is StoreUpdateMenuItem)
|
||||||
|
return StoreUpdateItemTemplate;
|
||||||
else if (item is SeperatorItem)
|
else if (item is SeperatorItem)
|
||||||
return SeperatorTemplate;
|
return SeperatorTemplate;
|
||||||
else if (item is AccountMenuItem)
|
else if (item is AccountMenuItem)
|
||||||
@@ -55,3 +58,5 @@ public partial class NavigationMenuTemplateSelector : DataTemplateSelector
|
|||||||
return MenuItemTemplate;
|
return MenuItemTemplate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -293,6 +293,19 @@ public class NotificationBuilder : INotificationBuilder
|
|||||||
ShowToast(builder);
|
ShowToast(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void CreateStoreUpdateNotification()
|
||||||
|
{
|
||||||
|
var builder = new ToastContentBuilder();
|
||||||
|
builder.SetToastScenario(ToastScenario.Default);
|
||||||
|
|
||||||
|
builder.AddText(Translator.Notifications_StoreUpdateAvailableTitle);
|
||||||
|
builder.AddText(Translator.Notifications_StoreUpdateAvailableMessage);
|
||||||
|
builder.AddArgument(Constants.ToastStoreUpdateActionKey, Constants.ToastStoreUpdateActionInstall);
|
||||||
|
builder.AddButton(GetDismissButton());
|
||||||
|
|
||||||
|
ShowToast(builder, "store-update-available");
|
||||||
|
}
|
||||||
|
|
||||||
public Task CreateCalendarReminderNotificationAsync(CalendarItem calendarItem, long reminderDurationInSeconds)
|
public Task CreateCalendarReminderNotificationAsync(CalendarItem calendarItem, long reminderDurationInSeconds)
|
||||||
{
|
{
|
||||||
if (calendarItem == null)
|
if (calendarItem == null)
|
||||||
@@ -437,3 +450,4 @@ public class NotificationBuilder : INotificationBuilder
|
|||||||
return SupportedIconScales.OrderBy(s => Math.Abs(s - requestedScale)).First();
|
return SupportedIconScales.OrderBy(s => Math.Abs(s - requestedScale)).First();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -308,6 +308,11 @@ public class PreferencesService(IConfigurationService configurationService) : Ob
|
|||||||
set => SetPropertyAndSave(nameof(EmailSyncIntervalMinutes), value);
|
set => SetPropertyAndSave(nameof(EmailSyncIntervalMinutes), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsStoreUpdateNotificationsEnabled
|
||||||
|
{
|
||||||
|
get => _configurationService.Get(nameof(IsStoreUpdateNotificationsEnabled), true);
|
||||||
|
set => SetPropertyAndSave(nameof(IsStoreUpdateNotificationsEnabled), value);
|
||||||
|
}
|
||||||
public WinoApplicationMode DefaultApplicationMode
|
public WinoApplicationMode DefaultApplicationMode
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -357,3 +362,5 @@ public class PreferencesService(IConfigurationService configurationService) : Ob
|
|||||||
return daysOfWeek;
|
return daysOfWeek;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Windows.Services.Store;
|
||||||
|
using Wino.Core.Domain.Interfaces;
|
||||||
|
|
||||||
|
namespace Wino.Mail.WinUI.Services;
|
||||||
|
|
||||||
|
public class StoreUpdateService : IStoreUpdateService
|
||||||
|
{
|
||||||
|
private const string NotificationShownKeyFormat = "StoreUpdateNotificationShown_{0}";
|
||||||
|
|
||||||
|
private readonly IConfigurationService _configurationService;
|
||||||
|
private readonly INotificationBuilder _notificationBuilder;
|
||||||
|
private readonly IPreferencesService _preferencesService;
|
||||||
|
private readonly INativeAppService _nativeAppService;
|
||||||
|
private readonly SemaphoreSlim _refreshSemaphore = new(1, 1);
|
||||||
|
private readonly StoreContext _storeContext = StoreContext.GetDefault();
|
||||||
|
|
||||||
|
public bool HasAvailableUpdate { get; private set; }
|
||||||
|
|
||||||
|
public StoreUpdateService(IConfigurationService configurationService,
|
||||||
|
INotificationBuilder notificationBuilder,
|
||||||
|
IPreferencesService preferencesService,
|
||||||
|
INativeAppService nativeAppService)
|
||||||
|
{
|
||||||
|
_configurationService = configurationService;
|
||||||
|
_notificationBuilder = notificationBuilder;
|
||||||
|
_preferencesService = preferencesService;
|
||||||
|
_nativeAppService = nativeAppService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> RefreshAvailabilityAsync(bool showNotification = false)
|
||||||
|
{
|
||||||
|
await _refreshSemaphore.WaitAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var updates = await _storeContext.GetAppAndOptionalStorePackageUpdatesAsync();
|
||||||
|
HasAvailableUpdate = updates?.Count > 0;
|
||||||
|
|
||||||
|
if (showNotification &&
|
||||||
|
HasAvailableUpdate &&
|
||||||
|
_preferencesService.IsStoreUpdateNotificationsEnabled &&
|
||||||
|
!HasShownNotificationForCurrentVersion())
|
||||||
|
{
|
||||||
|
_notificationBuilder.CreateStoreUpdateNotification();
|
||||||
|
MarkNotificationShownForCurrentVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
return HasAvailableUpdate;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
HasAvailableUpdate = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_refreshSemaphore.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> StartUpdateAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var updates = await _storeContext.GetAppAndOptionalStorePackageUpdatesAsync();
|
||||||
|
|
||||||
|
if (updates == null || updates.Count == 0)
|
||||||
|
{
|
||||||
|
HasAvailableUpdate = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _storeContext.RequestDownloadAndInstallStorePackageUpdatesAsync(updates);
|
||||||
|
await RefreshAvailabilityAsync(false).ConfigureAwait(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool HasShownNotificationForCurrentVersion()
|
||||||
|
=> _configurationService.Get(GetNotificationShownKey(), false);
|
||||||
|
|
||||||
|
private void MarkNotificationShownForCurrentVersion()
|
||||||
|
=> _configurationService.Set(GetNotificationShownKey(), true);
|
||||||
|
|
||||||
|
private string GetNotificationShownKey()
|
||||||
|
=> string.Format(NotificationShownKeyFormat, _nativeAppService.GetFullAppVersion().Replace(".", "_"));
|
||||||
|
}
|
||||||
@@ -62,6 +62,14 @@
|
|||||||
</coreControls:WinoNavigationViewItem.Icon>
|
</coreControls:WinoNavigationViewItem.Icon>
|
||||||
</coreControls:WinoNavigationViewItem>
|
</coreControls:WinoNavigationViewItem>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
<!-- Store Update Item -->
|
||||||
|
<DataTemplate x:Key="StoreUpdateItemTemplate" x:DataType="menu:StoreUpdateMenuItem">
|
||||||
|
<coreControls:WinoNavigationViewItem Content="{x:Bind domain:Translator.MenuUpdateAvailable}" DataContext="{x:Bind}">
|
||||||
|
<muxc:NavigationViewItem.Icon>
|
||||||
|
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="" />
|
||||||
|
</muxc:NavigationViewItem.Icon>
|
||||||
|
</coreControls:WinoNavigationViewItem>
|
||||||
|
</DataTemplate>
|
||||||
|
|
||||||
<!-- Rating Item -->
|
<!-- Rating Item -->
|
||||||
<DataTemplate x:Key="RatingItemTemplate" x:DataType="menu:RateMenuItem">
|
<DataTemplate x:Key="RatingItemTemplate" x:DataType="menu:RateMenuItem">
|
||||||
@@ -271,3 +279,7 @@
|
|||||||
<!--#endregion-->
|
<!--#endregion-->
|
||||||
|
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -304,6 +304,12 @@
|
|||||||
<TextBlock VerticalAlignment="Center" Text="{x:Bind domain:Translator.MenuSettings}" />
|
<TextBlock VerticalAlignment="Center" Text="{x:Bind domain:Translator.MenuSettings}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ListViewItem>
|
</ListViewItem>
|
||||||
|
<ListViewItem Visibility="{x:Bind ViewModel.IsStoreUpdateItemVisible, Mode=OneWay}">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="12">
|
||||||
|
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="" />
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="{x:Bind domain:Translator.MenuUpdateAvailable}" />
|
||||||
|
</StackPanel>
|
||||||
|
</ListViewItem>
|
||||||
</ListView.Items>
|
</ListView.Items>
|
||||||
</ListView>
|
</ListView>
|
||||||
</Grid>
|
</Grid>
|
||||||
@@ -398,3 +404,5 @@
|
|||||||
</abstract:CalendarAppShellAbstract>
|
</abstract:CalendarAppShellAbstract>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,12 @@
|
|||||||
<PathIcon Data="F1 M 0 9.375 C 0 8.509115 0.110677 7.677409 0.332031 6.879883 C 0.553385 6.082357 0.867513 5.335287 1.274414 4.638672 C 1.681315 3.942059 2.169596 3.30892 2.739258 2.739258 C 3.308919 2.169598 3.942057 1.681316 4.638672 1.274414 C 5.335286 0.867514 6.082356 0.553387 6.879883 0.332031 C 7.677409 0.110678 8.509114 0 9.375 0 C 10.234375 0 11.062825 0.112305 11.860352 0.336914 C 12.657877 0.561523 13.404947 0.877279 14.101562 1.28418 C 14.798176 1.691082 15.431314 2.179363 16.000977 2.749023 C 16.570637 3.318686 17.058918 3.951824 17.46582 4.648438 C 17.872721 5.345053 18.188477 6.092123 18.413086 6.889648 C 18.637695 7.687175 18.75 8.515625 18.75 9.375 C 18.75 10.240886 18.637695 11.072592 18.413086 11.870117 C 18.188477 12.667644 17.872721 13.413086 17.46582 14.106445 C 17.058918 14.799805 16.570637 15.431315 16.000977 16.000977 C 15.431314 16.570639 14.799804 17.05892 14.106445 17.46582 C 13.413085 17.872721 12.666015 18.188477 11.865234 18.413086 C 11.064453 18.637695 10.234375 18.75 9.375 18.75 C 8.509114 18.75 7.675781 18.639322 6.875 18.417969 C 6.074219 18.196615 5.327148 17.882486 4.633789 17.475586 C 3.94043 17.068686 3.308919 16.580404 2.739258 16.010742 C 2.169596 15.441081 1.681315 14.80957 1.274414 14.116211 C 0.867513 13.422852 0.553385 12.675781 0.332031 11.875 C 0.110677 11.074219 0 10.240886 0 9.375 Z M 17.5 9.375 C 17.5 8.626303 17.403971 7.905273 17.211914 7.211914 C 17.019855 6.518556 16.746418 5.87077 16.391602 5.268555 C 16.036783 4.666342 15.613606 4.119467 15.12207 3.62793 C 14.630533 3.136395 14.083658 2.713217 13.481445 2.358398 C 12.879231 2.003582 12.231445 1.730145 11.538086 1.538086 C 10.844727 1.346029 10.123697 1.25 9.375 1.25 C 8.626302 1.25 7.905273 1.346029 7.211914 1.538086 C 6.518555 1.730145 5.870768 2.003582 5.268555 2.358398 C 4.666341 2.713217 4.119466 3.136395 3.62793 3.62793 C 3.136393 4.119467 2.713216 4.666342 2.358398 5.268555 C 2.003581 5.87077 1.730143 6.518556 1.538086 7.211914 C 1.346029 7.905273 1.25 8.626303 1.25 9.375 C 1.25 10.123698 1.346029 10.844727 1.538086 11.538086 C 1.730143 12.231445 2.001953 12.879232 2.353516 13.481445 C 2.705078 14.083659 3.128255 14.632162 3.623047 15.126953 C 4.117838 15.621745 4.666341 16.044922 5.268555 16.396484 C 5.870768 16.748047 6.518555 17.019857 7.211914 17.211914 C 7.905273 17.403971 8.626302 17.5 9.375 17.5 C 10.123697 17.5 10.844727 17.403971 11.538086 17.211914 C 12.231445 17.019857 12.879231 16.748047 13.481445 16.396484 C 14.083658 16.044922 14.63216 15.621745 15.126953 15.126953 C 15.621744 14.632162 16.044922 14.083659 16.396484 13.481445 C 16.748047 12.879232 17.019855 12.231445 17.211914 11.538086 C 17.403971 10.844727 17.5 10.123698 17.5 9.375 Z M 9.375 10 C 9.205729 10 9.059244 9.938151 8.935547 9.814453 C 8.811849 9.690756 8.75 9.544271 8.75 9.375 L 8.75 4.375 C 8.75 4.20573 8.811849 4.059246 8.935547 3.935547 C 9.059244 3.81185 9.205729 3.75 9.375 3.75 C 9.544271 3.75 9.690755 3.81185 9.814453 3.935547 C 9.93815 4.059246 10 4.20573 10 4.375 L 10 8.75 L 13.125 8.75 C 13.294271 8.75 13.440755 8.81185 13.564453 8.935547 C 13.68815 9.059245 13.75 9.205729 13.75 9.375 C 13.75 9.544271 13.68815 9.690756 13.564453 9.814453 C 13.440755 9.938151 13.294271 10 13.125 10 Z " />
|
<PathIcon Data="F1 M 0 9.375 C 0 8.509115 0.110677 7.677409 0.332031 6.879883 C 0.553385 6.082357 0.867513 5.335287 1.274414 4.638672 C 1.681315 3.942059 2.169596 3.30892 2.739258 2.739258 C 3.308919 2.169598 3.942057 1.681316 4.638672 1.274414 C 5.335286 0.867514 6.082356 0.553387 6.879883 0.332031 C 7.677409 0.110678 8.509114 0 9.375 0 C 10.234375 0 11.062825 0.112305 11.860352 0.336914 C 12.657877 0.561523 13.404947 0.877279 14.101562 1.28418 C 14.798176 1.691082 15.431314 2.179363 16.000977 2.749023 C 16.570637 3.318686 17.058918 3.951824 17.46582 4.648438 C 17.872721 5.345053 18.188477 6.092123 18.413086 6.889648 C 18.637695 7.687175 18.75 8.515625 18.75 9.375 C 18.75 10.240886 18.637695 11.072592 18.413086 11.870117 C 18.188477 12.667644 17.872721 13.413086 17.46582 14.106445 C 17.058918 14.799805 16.570637 15.431315 16.000977 16.000977 C 15.431314 16.570639 14.799804 17.05892 14.106445 17.46582 C 13.413085 17.872721 12.666015 18.188477 11.865234 18.413086 C 11.064453 18.637695 10.234375 18.75 9.375 18.75 C 8.509114 18.75 7.675781 18.639322 6.875 18.417969 C 6.074219 18.196615 5.327148 17.882486 4.633789 17.475586 C 3.94043 17.068686 3.308919 16.580404 2.739258 16.010742 C 2.169596 15.441081 1.681315 14.80957 1.274414 14.116211 C 0.867513 13.422852 0.553385 12.675781 0.332031 11.875 C 0.110677 11.074219 0 10.240886 0 9.375 Z M 17.5 9.375 C 17.5 8.626303 17.403971 7.905273 17.211914 7.211914 C 17.019855 6.518556 16.746418 5.87077 16.391602 5.268555 C 16.036783 4.666342 15.613606 4.119467 15.12207 3.62793 C 14.630533 3.136395 14.083658 2.713217 13.481445 2.358398 C 12.879231 2.003582 12.231445 1.730145 11.538086 1.538086 C 10.844727 1.346029 10.123697 1.25 9.375 1.25 C 8.626302 1.25 7.905273 1.346029 7.211914 1.538086 C 6.518555 1.730145 5.870768 2.003582 5.268555 2.358398 C 4.666341 2.713217 4.119466 3.136395 3.62793 3.62793 C 3.136393 4.119467 2.713216 4.666342 2.358398 5.268555 C 2.003581 5.87077 1.730143 6.518556 1.538086 7.211914 C 1.346029 7.905273 1.25 8.626303 1.25 9.375 C 1.25 10.123698 1.346029 10.844727 1.538086 11.538086 C 1.730143 12.231445 2.001953 12.879232 2.353516 13.481445 C 2.705078 14.083659 3.128255 14.632162 3.623047 15.126953 C 4.117838 15.621745 4.666341 16.044922 5.268555 16.396484 C 5.870768 16.748047 6.518555 17.019857 7.211914 17.211914 C 7.905273 17.403971 8.626302 17.5 9.375 17.5 C 10.123697 17.5 10.844727 17.403971 11.538086 17.211914 C 12.231445 17.019857 12.879231 16.748047 13.481445 16.396484 C 14.083658 16.044922 14.63216 15.621745 15.126953 15.126953 C 15.621744 14.632162 16.044922 14.083659 16.396484 13.481445 C 16.748047 12.879232 17.019855 12.231445 17.211914 11.538086 C 17.403971 10.844727 17.5 10.123698 17.5 9.375 Z M 9.375 10 C 9.205729 10 9.059244 9.938151 8.935547 9.814453 C 8.811849 9.690756 8.75 9.544271 8.75 9.375 L 8.75 4.375 C 8.75 4.20573 8.811849 4.059246 8.935547 3.935547 C 9.059244 3.81185 9.205729 3.75 9.375 3.75 C 9.544271 3.75 9.690755 3.81185 9.814453 3.935547 C 9.93815 4.059246 10 4.20573 10 4.375 L 10 8.75 L 13.125 8.75 C 13.294271 8.75 13.440755 8.81185 13.564453 8.935547 C 13.68815 9.059245 13.75 9.205729 13.75 9.375 C 13.75 9.544271 13.68815 9.690756 13.564453 9.814453 C 13.440755 9.938151 13.294271 10 13.125 10 Z " />
|
||||||
</controls:SettingsCard.HeaderIcon>
|
</controls:SettingsCard.HeaderIcon>
|
||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
|
<controls:SettingsCard Description="{x:Bind domain:Translator.SettingsAppPreferences_StoreUpdateNotifications_Description}" Header="{x:Bind domain:Translator.SettingsAppPreferences_StoreUpdateNotifications_Title}">
|
||||||
|
<ToggleSwitch IsOn="{x:Bind ViewModel.PreferencesService.IsStoreUpdateNotificationsEnabled, Mode=TwoWay}" />
|
||||||
|
<controls:SettingsCard.HeaderIcon>
|
||||||
|
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="" />
|
||||||
|
</controls:SettingsCard.HeaderIcon>
|
||||||
|
</controls:SettingsCard>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<VisualStateManager.VisualStateGroups>
|
<VisualStateManager.VisualStateGroups>
|
||||||
@@ -64,3 +70,6 @@
|
|||||||
</VisualStateManager.VisualStateGroups>
|
</VisualStateManager.VisualStateGroups>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</abstract:AppPreferencesPageAbstract>
|
</abstract:AppPreferencesPageAbstract>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user