Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show "You" for active account in mail rendering page #566

Merged
merged 3 commits into from
Feb 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 1 addition & 12 deletions Wino.Core.Domain/Entities/Shared/AccountContact.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,6 @@ public class AccountContact : IEquatable<AccountContact>
/// </summary>
public bool IsRootContact { get; set; }

/// <summary>
/// Short display name of the contact.
/// Eather Name or Address.
/// </summary>
public string ShortDisplayName => Address == Name || string.IsNullOrWhiteSpace(Name) ? $"{Address.ToLowerInvariant()};" : $"{Name};";

public string DisplayName => Address == Name || string.IsNullOrWhiteSpace(Name) ? Address.ToLowerInvariant() : $"{Name} <{Address.ToLowerInvariant()}>";

public override bool Equals(object obj)
{
return Equals(obj as AccountContact);
Expand All @@ -58,10 +50,7 @@ public bool Equals(AccountContact other)

public override int GetHashCode()
{
int hashCode = -1717786383;
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Address);
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Name);
return hashCode;
return HashCode.Combine(Address, Name);
}

public static bool operator ==(AccountContact left, AccountContact right)
Expand Down
1 change: 1 addition & 0 deletions Wino.Core.Domain/Translations/en_US/resources.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"AccountSettingsDialog_AccountName": "Sender Display Name",
"AccountSettingsDialog_AccountNamePlaceholder": "eg. John Doe",
"AddHyperlink": "Add",
"AccountContactNameYou": "You",
"AutoDiscoveryProgressMessage": "Searching for mail settings...",
"AppCloseBackgroundSynchronizationWarningTitle": "Background Synchronization",
"AppCloseTerminateBehaviorWarningMessageFirstLine": "You are terminating Wino Mail and your app close behavior is set to 'Terminate'.",
Expand Down
317 changes: 158 additions & 159 deletions Wino.Core.UWP/WinoApplication.cs

Large diffs are not rendered by default.

193 changes: 96 additions & 97 deletions Wino.Core.ViewModels/AboutPageViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,125 +6,124 @@
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces;

namespace Wino.Core.ViewModels
namespace Wino.Core.ViewModels;

public partial class AboutPageViewModel : CoreBaseViewModel
{
public partial class AboutPageViewModel : CoreBaseViewModel
private readonly IStoreRatingService _storeRatingService;
private readonly IMailDialogService _dialogService;
private readonly INativeAppService _nativeAppService;
private readonly IApplicationConfiguration _appInitializerService;
private readonly IClipboardService _clipboardService;
private readonly IFileService _fileService;
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 IPreferencesService PreferencesService { get; }

public AboutPageViewModel(IStoreRatingService storeRatingService,
IMailDialogService dialogService,
INativeAppService nativeAppService,
IPreferencesService preferencesService,
IApplicationConfiguration appInitializerService,
IClipboardService clipboardService,
IFileService fileService,
IWinoLogger logInitializer)
{
private readonly IStoreRatingService _storeRatingService;
private readonly IMailDialogService _dialogService;
private readonly INativeAppService _nativeAppService;
private readonly IApplicationConfiguration _appInitializerService;
private readonly IClipboardService _clipboardService;
private readonly IFileService _fileService;
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 IPreferencesService PreferencesService { get; }

public AboutPageViewModel(IStoreRatingService storeRatingService,
IMailDialogService dialogService,
INativeAppService nativeAppService,
IPreferencesService preferencesService,
IApplicationConfiguration appInitializerService,
IClipboardService clipboardService,
IFileService fileService,
IWinoLogger logInitializer)
{
_storeRatingService = storeRatingService;
_dialogService = dialogService;
_nativeAppService = nativeAppService;
_logInitializer = logInitializer;
_appInitializerService = appInitializerService;
_clipboardService = clipboardService;
_fileService = fileService;

PreferencesService = preferencesService;
}
_storeRatingService = storeRatingService;
_dialogService = dialogService;
_nativeAppService = nativeAppService;
_logInitializer = logInitializer;
_appInitializerService = appInitializerService;
_clipboardService = clipboardService;
_fileService = fileService;

PreferencesService = preferencesService;
}

protected override void OnActivated()
{
base.OnActivated();
protected override void OnActivated()
{
base.OnActivated();

PreferencesService.PreferenceChanged -= PreferencesChanged;
PreferencesService.PreferenceChanged += PreferencesChanged;
}
PreferencesService.PreferenceChanged -= PreferencesChanged;
PreferencesService.PreferenceChanged += PreferencesChanged;
}

protected override void OnDeactivated()
{
base.OnDeactivated();
protected override void OnDeactivated()
{
base.OnDeactivated();

PreferencesService.PreferenceChanged -= PreferencesChanged;
}
PreferencesService.PreferenceChanged -= PreferencesChanged;
}

private void PreferencesChanged(object sender, string e)
private void PreferencesChanged(object sender, string e)
{
if (e == nameof(PreferencesService.IsLoggingEnabled))
{
if (e == nameof(PreferencesService.IsLoggingEnabled))
{
_logInitializer.RefreshLoggingLevel();
}
_logInitializer.RefreshLoggingLevel();
}
}

[RelayCommand]
private async Task CopyDiagnosticId()
[RelayCommand]
private async Task CopyDiagnosticId()
{
try
{
try
{
await _clipboardService.CopyClipboardAsync(PreferencesService.DiagnosticId);
_dialogService.InfoBarMessage(Translator.Buttons_Copy, string.Format(Translator.ClipboardTextCopied_Message, "Id"), InfoBarMessageType.Success);
}
catch (Exception ex)
{
_dialogService.InfoBarMessage(Translator.GeneralTitle_Error, string.Format(Translator.ClipboardTextCopyFailed_Message, "Id"), InfoBarMessageType.Error);
Log.Error(ex, "Failed to copy diagnostic id to clipboard.");
}
await _clipboardService.CopyClipboardAsync(PreferencesService.DiagnosticId);
_dialogService.InfoBarMessage(Translator.Buttons_Copy, string.Format(Translator.ClipboardTextCopied_Message, "Id"), InfoBarMessageType.Success);
}

[RelayCommand]
private async Task ShareWinoLogAsync()
catch (Exception ex)
{
var appDataFolder = _appInitializerService.ApplicationDataFolderPath;
_dialogService.InfoBarMessage(Translator.GeneralTitle_Error, string.Format(Translator.ClipboardTextCopyFailed_Message, "Id"), InfoBarMessageType.Error);
Log.Error(ex, "Failed to copy diagnostic id to clipboard.");
}
}

var selectedFolderPath = await _dialogService.PickWindowsFolderAsync();
[RelayCommand]
private async Task ShareWinoLogAsync()
{
var appDataFolder = _appInitializerService.ApplicationDataFolderPath;

if (string.IsNullOrEmpty(selectedFolderPath)) return;
var selectedFolderPath = await _dialogService.PickWindowsFolderAsync();

var areLogsSaved = await _fileService.SaveLogsToFolderAsync(appDataFolder, selectedFolderPath).ConfigureAwait(false);
if (string.IsNullOrEmpty(selectedFolderPath)) return;

if (areLogsSaved)
{
_dialogService.InfoBarMessage(Translator.Info_LogsSavedTitle, string.Format(Translator.Info_LogsSavedMessage, Constants.LogArchiveFileName), InfoBarMessageType.Success);
}
else
{
_dialogService.InfoBarMessage(Translator.Info_LogsNotFoundTitle, Translator.Info_LogsNotFoundMessage, InfoBarMessageType.Error);
}
var areLogsSaved = await _fileService.SaveLogsToFolderAsync(appDataFolder, selectedFolderPath).ConfigureAwait(false);

if (areLogsSaved)
{
_dialogService.InfoBarMessage(Translator.Info_LogsSavedTitle, string.Format(Translator.Info_LogsSavedMessage, Constants.LogArchiveFileName), InfoBarMessageType.Success);
}
else
{
_dialogService.InfoBarMessage(Translator.Info_LogsNotFoundTitle, Translator.Info_LogsNotFoundMessage, InfoBarMessageType.Error);
}
}

[RelayCommand]
private async Task Navigate(object url)
[RelayCommand]
private async Task Navigate(object url)
{
if (url is string stringUrl)
{
if (url is string stringUrl)
if (stringUrl == "Store")
await ShowRateDialogAsync();
else
{
if (stringUrl == "Store")
await ShowRateDialogAsync();
else
{
// Discord disclaimer message about server.
if (stringUrl == DiscordChannelUrl)
await _dialogService.ShowMessageAsync(Translator.DiscordChannelDisclaimerMessage,
Translator.DiscordChannelDisclaimerTitle,
WinoCustomMessageDialogIcon.Warning);

await _nativeAppService.LaunchUriAsync(new Uri(stringUrl));
}
// Discord disclaimer message about server.
if (stringUrl == DiscordChannelUrl)
await _dialogService.ShowMessageAsync(Translator.DiscordChannelDisclaimerMessage,
Translator.DiscordChannelDisclaimerTitle,
WinoCustomMessageDialogIcon.Warning);

await _nativeAppService.LaunchUriAsync(new Uri(stringUrl));
}
}

private Task ShowRateDialogAsync() => _storeRatingService.LaunchStorePageForReviewAsync();
}

private Task ShowRateDialogAsync() => _storeRatingService.LaunchStorePageForReviewAsync();
}
37 changes: 37 additions & 0 deletions Wino.Mail.ViewModels/Data/AccountContactViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Wino.Core.Domain;
using Wino.Core.Domain.Entities.Shared;

namespace Wino.Mail.ViewModels.Data;

public class AccountContactViewModel: AccountContact
{
public AccountContactViewModel(AccountContact contact)
{
Address = contact.Address;
Name = contact.Name;
Base64ContactPicture = contact.Base64ContactPicture;
IsRootContact = contact.IsRootContact;
}

/// <summary>
/// Gets or sets whether the contact is the current account.
/// </summary>
public bool IsMe { get; set; }

/// <summary>
/// Provides a short name of the contact.
/// <see cref="ShortDisplayName"/> or "You"
/// </summary>
public string ShortNameOrYou => IsMe ? Translator.AccountContactNameYou : ShortDisplayName;

/// <summary>
/// Short display name of the contact.
/// Either Name or Address.
/// </summary>
public string ShortDisplayName => Address == Name || string.IsNullOrWhiteSpace(Name) ? $"{Address.ToLowerInvariant()};" : $"{Name};";

/// <summary>
/// Display name of the contact in a format: Name <Address>.
/// </summary>
public string DisplayName => Address == Name || string.IsNullOrWhiteSpace(Name) ? Address.ToLowerInvariant() : $"{Name} <{Address.ToLowerInvariant()}>";
}
37 changes: 19 additions & 18 deletions Wino.Mail.ViewModels/MailRenderingPageViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,35 +90,33 @@ public bool IsDarkWebviewRenderer

[ObservableProperty]
[NotifyPropertyChangedFor(nameof(ShouldDisplayDownloadProgress))]
private bool isIndetermineProgress;
public partial bool IsIndetermineProgress { get; set; }

[ObservableProperty]
[NotifyPropertyChangedFor(nameof(ShouldDisplayDownloadProgress))]
private double currentDownloadPercentage;
public partial double CurrentDownloadPercentage { get; set; }

[ObservableProperty]
[NotifyPropertyChangedFor(nameof(CanUnsubscribe))]
private MailRenderModel currentRenderModel;
public partial MailRenderModel CurrentRenderModel { get; set; }

[ObservableProperty]
private string subject;
public partial string Subject { get; set; }

[ObservableProperty]
private string fromAddress;
public partial string FromAddress { get; set; }

[ObservableProperty]
private string fromName;
public partial string FromName { get; set; }

[ObservableProperty]
private string contactPicture;
public partial string ContactPicture { get; set; }

[ObservableProperty]
private DateTime creationDate;


public ObservableCollection<AccountContact> ToItems { get; set; } = [];
public ObservableCollection<AccountContact> CcItems { get; set; } = [];
public ObservableCollection<AccountContact> BccItems { get; set; } = [];
public partial DateTime CreationDate { get; set; }
public ObservableCollection<AccountContactViewModel> ToItems { get; set; } = [];
public ObservableCollection<AccountContactViewModel> CcItems { get; set; } = [];
public ObservableCollection<AccountContactViewModel> BccItems { get; set; } = [];
public ObservableCollection<MailAttachmentViewModel> Attachments { get; set; } = [];
public ObservableCollection<MailOperationMenuItem> MenuItems { get; set; } = [];

Expand Down Expand Up @@ -467,24 +465,27 @@ await ExecuteUIThread(() =>
});
}

private async Task<List<AccountContact>> GetAccountContacts(InternetAddressList internetAddresses)
private async Task<List<AccountContactViewModel>> GetAccountContacts(InternetAddressList internetAddresses)
{
var accounts = new List<AccountContact>();
List<AccountContactViewModel> accounts = [];
foreach (var item in internetAddresses)
{
if (item is MailboxAddress mailboxAddress)
{
var foundContact = await _contactService.GetAddressInformationByAddressAsync(mailboxAddress.Address).ConfigureAwait(false)
?? new AccountContact() { Name = mailboxAddress.Name, Address = mailboxAddress.Address };

var contactViewModel = new AccountContactViewModel(foundContact);

// Make sure that user account first in the list.
if (foundContact.Address == initializedMailItemViewModel?.AssignedAccount?.Address)
if (string.Equals(contactViewModel.Address, initializedMailItemViewModel?.AssignedAccount?.Address, StringComparison.OrdinalIgnoreCase))
{
accounts.Insert(0, foundContact);
contactViewModel.IsMe = true;
accounts.Insert(0, contactViewModel);
}
else
{
accounts.Add(foundContact);
accounts.Add(contactViewModel);
}
}
else if (item is GroupAddress groupAddress)
Expand Down
4 changes: 2 additions & 2 deletions Wino.Mail/Views/MailRenderingPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@
mc:Ignorable="d">

<Page.Resources>
<DataTemplate x:Key="InternetAddressTemplate" x:DataType="entities:AccountContact">
<DataTemplate x:Key="InternetAddressTemplate" x:DataType="viewModelData:AccountContactViewModel">
<HyperlinkButton
Margin="-2,-2"
Padding="4,2"
Click="InternetAddressClicked"
Content="{x:Bind ShortDisplayName}"
Content="{x:Bind ShortNameOrYou}"
ToolTipService.ToolTip="{x:Bind DisplayName}">
<HyperlinkButton.ContextFlyout>
<Flyout Placement="Bottom">
Expand Down
2 changes: 1 addition & 1 deletion Wino.Services/ContactService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public Task<List<AccountContact>> GetAddressInformationAsync(string queryText)
}

public Task<AccountContact> GetAddressInformationByAddressAsync(string address)
=> Connection.Table<AccountContact>().Where(a => a.Address == address).FirstOrDefaultAsync();
=> Connection.Table<AccountContact>().FirstOrDefaultAsync(a => a.Address == address);

public async Task SaveAddressInformationAsync(MimeMessage message)
{
Expand Down
Loading