Contact and settings updates.
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
namespace Wino.Core.Domain;
|
||||
|
||||
public static class AppUrls
|
||||
{
|
||||
public const string Website = "https://www.winomail.app";
|
||||
public const string Discord = "https://discord.gg/windows-apps-hub-714581497222398064";
|
||||
public const string GitHub = "https://github.com/bkaankose/Wino-Mail/";
|
||||
public const string PrivacyPolicy = "https://www.winomail.app/support/privacy";
|
||||
public const string Paypal = "https://paypal.me/bkaankose?country.x=PL&locale.x=en_US";
|
||||
}
|
||||
@@ -763,6 +763,8 @@
|
||||
"SettingsPrefer24HourClock_Title": "Display Clock Format in 24 Hours",
|
||||
"SettingsPrivacyPolicy_Description": "Review privacy policy.",
|
||||
"SettingsPrivacyPolicy_Title": "Privacy Policy",
|
||||
"SettingsWebsite_Description": "Open the Wino Mail website.",
|
||||
"SettingsWebsite_Title": "Website",
|
||||
"SettingsReadComposePane_Description": "Fonts, external content.",
|
||||
"SettingsReadComposePane_Title": "Reader & Composer",
|
||||
"SettingsReader_Title": "Reader",
|
||||
@@ -864,6 +866,7 @@
|
||||
"SystemFolderConfigSetupSuccess_Message": "System folders are successfully configured.",
|
||||
"SystemFolderConfigSetupSuccess_Title": "System Folders Setup",
|
||||
"SystemTrayMenu_ShowWino": "Open Wino Mail",
|
||||
"SystemTrayMenu_ShowWinoCalendar": "Open Wino Calendar",
|
||||
"SystemTrayMenu_ExitWino": "Exit",
|
||||
"TestingImapConnectionMessage": "Testing server connection...",
|
||||
"TitleBarServerDisconnectedButton_Description": "Wino is disconnected from the network. Click reconnect to restore connection.",
|
||||
|
||||
@@ -21,10 +21,11 @@ public partial class AboutPageViewModel : CoreBaseViewModel
|
||||
private readonly IWinoLogger _logInitializer;
|
||||
|
||||
public string VersionName => _nativeAppService.GetFullAppVersion();
|
||||
public string DiscordChannelUrl => "https://discord.gg/windows-apps-hub-714581497222398064";
|
||||
public string GitHubUrl => "https://github.com/bkaankose/Wino-Mail/";
|
||||
public string PrivacyPolicyUrl => "https://www.winomail.app/support/privacy";
|
||||
public string PaypalUrl => "https://paypal.me/bkaankose?country.x=PL&locale.x=en_US";
|
||||
public string WebsiteUrl => AppUrls.Website;
|
||||
public string DiscordChannelUrl => AppUrls.Discord;
|
||||
public string GitHubUrl => AppUrls.GitHub;
|
||||
public string PrivacyPolicyUrl => AppUrls.PrivacyPolicy;
|
||||
public string PaypalUrl => AppUrls.Paypal;
|
||||
|
||||
public IPreferencesService PreferencesService { get; }
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@ public partial class SettingOptionsPageViewModel : CoreBaseViewModel
|
||||
private readonly INativeAppService _nativeAppService;
|
||||
private readonly IAccountService _accountService;
|
||||
|
||||
public string WebsiteUrl => AppUrls.Website;
|
||||
public string PaypalUrl => AppUrls.Paypal;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string VersionText { get; set; } = string.Empty;
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ using Wino.Core.Domain.Entities.Shared;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models.Navigation;
|
||||
using Wino.Mail.ViewModels.Data;
|
||||
|
||||
namespace Wino.Mail.ViewModels;
|
||||
|
||||
@@ -56,8 +57,8 @@ public partial class ContactsPageViewModel : MailBaseViewModel
|
||||
public bool CanLoadMoreContacts => HasMoreContacts && !IsLoading && !IsLoadingMore;
|
||||
public bool CanDeleteSelectedContacts => SelectedContactsCount > 0;
|
||||
|
||||
public ObservableCollection<AccountContact> Contacts { get; } = new();
|
||||
public ObservableCollection<AccountContact> SelectedContacts { get; } = new();
|
||||
public ObservableCollection<AccountContactViewModel> Contacts { get; } = new();
|
||||
public ObservableCollection<AccountContactViewModel> SelectedContacts { get; } = new();
|
||||
|
||||
public ContactsPageViewModel(IContactService contactService, IMailDialogService dialogService)
|
||||
{
|
||||
@@ -150,7 +151,7 @@ public partial class ContactsPageViewModel : MailBaseViewModel
|
||||
|
||||
foreach (var contact in page.Contacts)
|
||||
{
|
||||
Contacts.Add(contact);
|
||||
Contacts.Add(new AccountContactViewModel(contact));
|
||||
}
|
||||
|
||||
TotalContactsCount = page.TotalCount;
|
||||
@@ -217,8 +218,9 @@ public partial class ContactsPageViewModel : MailBaseViewModel
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task EditContactAsync(AccountContact contact)
|
||||
private async Task EditContactAsync(AccountContactViewModel contactViewModel)
|
||||
{
|
||||
var contact = contactViewModel?.SourceContact;
|
||||
if (contact == null) return;
|
||||
|
||||
var result = await _dialogService.ShowEditContactDialogAsync(contact);
|
||||
@@ -249,8 +251,9 @@ public partial class ContactsPageViewModel : MailBaseViewModel
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task DeleteContactAsync(AccountContact contact)
|
||||
private async Task DeleteContactAsync(AccountContactViewModel contactViewModel)
|
||||
{
|
||||
var contact = contactViewModel?.SourceContact;
|
||||
if (contact == null || contact.IsRootContact)
|
||||
{
|
||||
_dialogService.InfoBarMessage(
|
||||
@@ -277,6 +280,7 @@ public partial class ContactsPageViewModel : MailBaseViewModel
|
||||
if (SelectedContacts.Count == 0) return;
|
||||
|
||||
var deletableContacts = SelectedContacts
|
||||
.Select(c => c?.SourceContact)
|
||||
.Where(c => c != null && !c.IsRootContact)
|
||||
.GroupBy(c => c.Address, StringComparer.OrdinalIgnoreCase)
|
||||
.Select(g => g.First())
|
||||
@@ -366,8 +370,9 @@ public partial class ContactsPageViewModel : MailBaseViewModel
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task PickContactPhotoAsync(AccountContact contact)
|
||||
private async Task PickContactPhotoAsync(AccountContactViewModel contactViewModel)
|
||||
{
|
||||
var contact = contactViewModel?.SourceContact;
|
||||
if (contact == null) return;
|
||||
|
||||
try
|
||||
@@ -410,7 +415,7 @@ public partial class ContactsPageViewModel : MailBaseViewModel
|
||||
});
|
||||
}
|
||||
|
||||
private static void ReplaceContactByAddress(ObservableCollection<AccountContact> source, AccountContact updatedContact)
|
||||
private static void ReplaceContactByAddress(ObservableCollection<AccountContactViewModel> source, AccountContact updatedContact)
|
||||
{
|
||||
var index = source
|
||||
.Select((item, i) => new { item, i })
|
||||
@@ -419,7 +424,7 @@ public partial class ContactsPageViewModel : MailBaseViewModel
|
||||
|
||||
if (index < 0) return;
|
||||
|
||||
source[index] = CloneContact(updatedContact);
|
||||
source[index] = new AccountContactViewModel(CloneContact(updatedContact));
|
||||
}
|
||||
|
||||
private static AccountContact CloneContact(AccountContact contact)
|
||||
|
||||
@@ -8,17 +8,23 @@ namespace Wino.Mail.ViewModels.Data;
|
||||
|
||||
public partial class AccountContactViewModel : ObservableObject, IMailItemDisplayInformation
|
||||
{
|
||||
public AccountContact SourceContact { get; }
|
||||
public string Address { get; set; }
|
||||
public string Name { get; set; }
|
||||
public Guid? ContactPictureFileId { get; set; }
|
||||
public string Base64ContactPicture { get; set; }
|
||||
public bool IsRootContact { get; set; }
|
||||
public bool IsOverridden { get; set; }
|
||||
|
||||
public AccountContactViewModel(AccountContact contact)
|
||||
{
|
||||
SourceContact = contact;
|
||||
Address = contact.Address;
|
||||
Name = contact.Name;
|
||||
ContactPictureFileId = contact.ContactPictureFileId;
|
||||
Base64ContactPicture = contact.Base64ContactPicture;
|
||||
IsRootContact = contact.IsRootContact;
|
||||
IsOverridden = contact.IsOverridden;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -68,7 +74,9 @@ public partial class AccountContactViewModel : ObservableObject, IMailItemDispla
|
||||
{
|
||||
Address = Address,
|
||||
Name = Name,
|
||||
ContactPictureFileId = ContactPictureFileId,
|
||||
Base64ContactPicture = Base64ContactPicture,
|
||||
IsRootContact = IsRootContact
|
||||
IsRootContact = IsRootContact,
|
||||
IsOverridden = IsOverridden
|
||||
};
|
||||
}
|
||||
|
||||
@@ -73,7 +73,6 @@ public sealed partial class ImagePreviewControl : PersonPicture
|
||||
|
||||
RequestRefresh();
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
RequestRefresh();
|
||||
@@ -306,7 +305,6 @@ public sealed partial class ImagePreviewControl : PersonPicture
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private async Task ApplyInitialVisualStateAsync(string displayName, long refreshVersion, CancellationToken cancellationToken)
|
||||
{
|
||||
await ExecuteOnUiThreadAsync(() =>
|
||||
|
||||
@@ -107,9 +107,6 @@
|
||||
</controls:Segmented>
|
||||
</StackPanel>
|
||||
</TitleBar.RightHeader>
|
||||
<TitleBar.IconSource>
|
||||
<ImageIconSource ImageSource="/Assets/Wino_Icon.ico" />
|
||||
</TitleBar.IconSource>
|
||||
</TitleBar>
|
||||
|
||||
<Frame
|
||||
@@ -127,6 +124,7 @@
|
||||
<notifyicon:TaskbarIcon.ContextFlyout>
|
||||
<MenuFlyout AreOpenCloseAnimationsEnabled="False">
|
||||
<MenuFlyoutItem Command="{x:Bind ShowWinoCommand}" Text="{x:Bind domain:Translator.SystemTrayMenu_ShowWino}" />
|
||||
<MenuFlyoutItem Command="{x:Bind ShowWinoCalendarCommand}" Text="{x:Bind domain:Translator.SystemTrayMenu_ShowWinoCalendar}" />
|
||||
<MenuFlyoutSeparator />
|
||||
<MenuFlyoutItem Command="{x:Bind ExitWinoCommand}" Text="{x:Bind domain:Translator.SystemTrayMenu_ExitWino}" />
|
||||
</MenuFlyout>
|
||||
|
||||
@@ -34,6 +34,7 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow,
|
||||
public INavigationService NavigationService { get; } = WinoApplication.Current.Services.GetService<INavigationService>() ?? throw new Exception("NavigationService not registered in DI container.");
|
||||
|
||||
public ICommand ShowWinoCommand { get; set; }
|
||||
public ICommand ShowWinoCalendarCommand { get; set; }
|
||||
public ICommand ExitWinoCommand { get; set; }
|
||||
|
||||
public ObservableCollection<SynchronizationActionItem> SyncActionItems { get; } = new();
|
||||
@@ -60,7 +61,8 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow,
|
||||
// Register global mouse button listener for back button
|
||||
RegisterMouseBackButtonListener();
|
||||
|
||||
ShowWinoCommand = new RelayCommand(RestoreFromTray);
|
||||
ShowWinoCommand = new RelayCommand(() => RestoreAndSwitchMode(WinoApplicationMode.Mail));
|
||||
ShowWinoCalendarCommand = new RelayCommand(() => RestoreAndSwitchMode(WinoApplicationMode.Calendar));
|
||||
ExitWinoCommand = new RelayCommand(ForceClose);
|
||||
|
||||
this.SetIcon("Assets/Wino_Icon.ico");
|
||||
@@ -281,6 +283,18 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow,
|
||||
BringToFront();
|
||||
}
|
||||
|
||||
private void RestoreAndSwitchMode(WinoApplicationMode mode)
|
||||
{
|
||||
_currentMode = mode;
|
||||
|
||||
_isApplyingActivationMode = true;
|
||||
AppModeSegmentedControl.SelectedIndex = mode == WinoApplicationMode.Mail ? 0 : 1;
|
||||
_isApplyingActivationMode = false;
|
||||
|
||||
NavigationService.ChangeApplicationMode(mode);
|
||||
RestoreFromTray();
|
||||
}
|
||||
|
||||
public void ForceClose()
|
||||
{
|
||||
// Unsubscribe from the closing event to avoid infinite loop
|
||||
|
||||
@@ -49,8 +49,6 @@ public sealed partial class AccountDetailsPage : AccountDetailsPageAbstract
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
if (e.NavigationMode == NavigationMode.New)
|
||||
{
|
||||
var targetTabIndex = ViewModel.SelectedTabIndex;
|
||||
if (targetTabIndex < 0 || targetTabIndex >= TabSelector.Items.Count)
|
||||
{
|
||||
@@ -59,5 +57,4 @@ public sealed partial class AccountDetailsPage : AccountDetailsPageAbstract
|
||||
|
||||
TabSelector.SelectedItem = TabSelector.Items[targetTabIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,19 +33,12 @@
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- App Icon -->
|
||||
<Border
|
||||
Width="72"
|
||||
Height="72"
|
||||
Background="{ThemeResource AccentFillColorDefaultBrush}"
|
||||
CornerRadius="16">
|
||||
<FontIcon
|
||||
HorizontalAlignment="Center"
|
||||
<Image
|
||||
Width="96"
|
||||
Height="96"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="32"
|
||||
Foreground="{ThemeResource TextOnAccentFillColorPrimaryBrush}"
|
||||
Glyph="" />
|
||||
</Border>
|
||||
Source="ms-appx:///Assets/AppEntries/MailAssets/Square150x150Logo.scale-100.png"
|
||||
Stretch="Uniform" />
|
||||
|
||||
<!-- App Info -->
|
||||
<StackPanel
|
||||
@@ -65,6 +58,17 @@
|
||||
Foreground="{ThemeResource TextFillColorTertiaryBrush}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind ViewModel.VersionText, Mode=OneWay}" />
|
||||
<StackPanel
|
||||
Margin="0,8,0,0"
|
||||
Orientation="Horizontal"
|
||||
Spacing="8">
|
||||
<HyperlinkButton
|
||||
Content="{x:Bind ViewModel.WebsiteUrl, Mode=OneWay}"
|
||||
NavigateUri="{x:Bind ViewModel.WebsiteUrl, Mode=OneWay}" />
|
||||
<HyperlinkButton
|
||||
Content="{x:Bind domain:Translator.SettingsPaypal_Title}"
|
||||
NavigateUri="{x:Bind ViewModel.PaypalUrl, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
|
||||
@@ -17,9 +17,12 @@
|
||||
</TransitionCollection>
|
||||
</StackPanel.ChildrenTransitions>
|
||||
<Image
|
||||
Width="50"
|
||||
Height="50"
|
||||
Source="ms-appx:///Images/StoreLogo.png" />
|
||||
Width="128"
|
||||
Height="128"
|
||||
Margin="0,0,0,12"
|
||||
HorizontalAlignment="Center"
|
||||
Source="ms-appx:///Assets/AppEntries/MailAssets/Square150x150Logo.scale-100.png"
|
||||
Stretch="Uniform" />
|
||||
<TextBlock
|
||||
Margin="0,6,0,4"
|
||||
HorizontalAlignment="Center"
|
||||
@@ -32,6 +35,26 @@
|
||||
Style="{StaticResource BodyTextBlockStyle}"
|
||||
Text="{x:Bind domain:Translator.SettingsAboutWinoDescription}" />
|
||||
|
||||
<controls:SettingsCard
|
||||
Command="{x:Bind ViewModel.NavigateCommand}"
|
||||
CommandParameter="{x:Bind ViewModel.WebsiteUrl}"
|
||||
Description="{x:Bind domain:Translator.SettingsWebsite_Description}"
|
||||
Header="{x:Bind domain:Translator.SettingsWebsite_Title}"
|
||||
IsClickEnabled="True">
|
||||
<controls:SettingsCard.HeaderIcon>
|
||||
<FontIcon
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Glyph="" />
|
||||
</controls:SettingsCard.HeaderIcon>
|
||||
<controls:SettingsCard.ActionIcon>
|
||||
<PathIcon
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Data="{StaticResource OpenInNewWindowPathIcon}" />
|
||||
</controls:SettingsCard.ActionIcon>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard
|
||||
Command="{x:Bind ViewModel.NavigateCommand}"
|
||||
CommandParameter="{x:Bind ViewModel.GitHubUrl}"
|
||||
@@ -174,7 +197,7 @@
|
||||
|
||||
<controls:SettingsCard Header="Wino Mail">
|
||||
<controls:SettingsCard.HeaderIcon>
|
||||
<BitmapIcon ShowAsMonochrome="False" UriSource="ms-appx:///Images/StoreLogo.png" />
|
||||
<BitmapIcon ShowAsMonochrome="False" UriSource="ms-appx:///Assets/AppEntries/MailAssets/Square150x150Logo.scale-100.png" />
|
||||
</controls:SettingsCard.HeaderIcon>
|
||||
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" IsTextSelectionEnabled="True">
|
||||
<Run Text="{x:Bind domain:Translator.SettingsAboutVersion}" /><Run Text="{x:Bind ViewModel.VersionName}" />
|
||||
|
||||
@@ -3,18 +3,20 @@
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:abstract="using:Wino.Views.Abstract"
|
||||
xmlns:controls="using:Wino.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:domain="using:Wino.Core.Domain"
|
||||
xmlns:entities="using:Wino.Core.Domain.Entities.Shared"
|
||||
xmlns:helpers="using:Wino.Helpers"
|
||||
xmlns:listview="using:Wino.Mail.WinUI.Controls.ListView"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:viewModels="using:Wino.Mail.ViewModels.Data"
|
||||
xmlns:toolkitExt="using:CommunityToolkit.WinUI"
|
||||
x:Name="root"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Page.Resources>
|
||||
<DataTemplate x:Key="ContactTemplate" x:DataType="entities:AccountContact">
|
||||
<DataTemplate x:Key="ContactTemplate" x:DataType="viewModels:AccountContactViewModel">
|
||||
<Grid Margin="0,0,0,8" Padding="0,4">
|
||||
<Border
|
||||
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
|
||||
@@ -29,12 +31,11 @@
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<PersonPicture
|
||||
<controls:ImagePreviewControl
|
||||
Grid.Column="0"
|
||||
Width="40"
|
||||
Height="40"
|
||||
DisplayName="{x:Bind Name, Mode=OneTime, TargetNullValue=''}"
|
||||
ProfilePicture="{x:Bind helpers:XamlHelpers.Base64ToBitmapImage(Base64ContactPicture), Mode=OneWay}" />
|
||||
MailItemInformation="{x:Bind Mode=OneWay}" />
|
||||
|
||||
<StackPanel
|
||||
Grid.Column="1"
|
||||
|
||||
@@ -2,8 +2,8 @@ using System;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Wino.Core.Domain.Entities.Shared;
|
||||
using Wino.Mail.ViewModels;
|
||||
using Wino.Mail.ViewModels.Data;
|
||||
using Wino.Views.Abstract;
|
||||
|
||||
namespace Wino.Views.Settings;
|
||||
@@ -20,7 +20,7 @@ public sealed partial class ContactsPage : ContactsPageAbstract
|
||||
|
||||
private void EditContact_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button && button.CommandParameter is AccountContact contact)
|
||||
if (sender is Button button && button.CommandParameter is AccountContactViewModel contact)
|
||||
{
|
||||
ViewModel.EditContactCommand.Execute(contact);
|
||||
}
|
||||
@@ -28,7 +28,7 @@ public sealed partial class ContactsPage : ContactsPageAbstract
|
||||
|
||||
private void PickContactPhoto_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button && button.CommandParameter is AccountContact contact)
|
||||
if (sender is Button button && button.CommandParameter is AccountContactViewModel contact)
|
||||
{
|
||||
ViewModel.PickContactPhotoCommand.Execute(contact);
|
||||
}
|
||||
@@ -36,7 +36,7 @@ public sealed partial class ContactsPage : ContactsPageAbstract
|
||||
|
||||
private void DeleteContact_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button && button.CommandParameter is AccountContact contact)
|
||||
if (sender is Button button && button.CommandParameter is AccountContactViewModel contact)
|
||||
{
|
||||
ViewModel.DeleteContactCommand.Execute(contact);
|
||||
}
|
||||
@@ -53,7 +53,7 @@ public sealed partial class ContactsPage : ContactsPageAbstract
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var removedItem in e.RemovedItems.OfType<AccountContact>())
|
||||
foreach (var removedItem in e.RemovedItems.OfType<AccountContactViewModel>())
|
||||
{
|
||||
var selectedContact = ViewModel.SelectedContacts.FirstOrDefault(c =>
|
||||
string.Equals(c.Address, removedItem.Address, StringComparison.OrdinalIgnoreCase));
|
||||
@@ -64,7 +64,7 @@ public sealed partial class ContactsPage : ContactsPageAbstract
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var addedItem in e.AddedItems.OfType<AccountContact>())
|
||||
foreach (var addedItem in e.AddedItems.OfType<AccountContactViewModel>())
|
||||
{
|
||||
var alreadySelected = ViewModel.SelectedContacts.Any(c =>
|
||||
string.Equals(c.Address, addedItem.Address, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
Reference in New Issue
Block a user