diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..c686ec1f
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,290 @@
+# Remove the line below if you want to inherit .editorconfig settings from higher directories
+root = true
+
+[*]
+trim_trailing_whitespace = true
+insert_final_newline = true
+dotnet_style_operator_placement_when_wrapping = beginning_of_line
+tab_width = 4
+indent_size = 4
+end_of_line = crlf
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_null_propagation = true:suggestion
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
+dotnet_style_prefer_auto_properties = true:silent
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
+dotnet_style_prefer_conditional_expression_over_assignment = true:silent
+dotnet_style_prefer_conditional_expression_over_return = true:silent
+dotnet_style_explicit_tuple_names = true:suggestion
+dotnet_style_prefer_inferred_tuple_names = true:suggestion
+dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
+dotnet_style_prefer_compound_assignment = true:suggestion
+dotnet_style_prefer_simplified_interpolation = true:suggestion
+dotnet_style_namespace_match_folder = true:suggestion
+dotnet_style_readonly_field = true:suggestion
+dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
+dotnet_style_predefined_type_for_member_access = true:suggestion
+dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
+dotnet_style_allow_multiple_blank_lines_experimental = true:silent
+dotnet_style_allow_statement_immediately_after_block_experimental = true:silent
+dotnet_code_quality_unused_parameters = all:suggestion
+dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
+dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
+dotnet_style_qualification_for_field = false:silent
+dotnet_style_qualification_for_property = false:silent
+dotnet_style_qualification_for_event = false:silent
+dotnet_style_qualification_for_method = false:silent
+
+# C# files
+[*.cs]
+
+#### Core EditorConfig Options ####
+
+# Indentation and spacing
+indent_size = 4
+indent_style = space
+tab_width = 4
+
+# New line preferences
+end_of_line = crlf
+
+#### .NET Coding Conventions ####
+
+# Organize usings
+dotnet_separate_import_directive_groups = false
+dotnet_sort_system_directives_first = true
+file_header_template = unset
+
+# this. and Me. preferences
+dotnet_style_qualification_for_event = false
+dotnet_style_qualification_for_field = false
+dotnet_style_qualification_for_method = false
+dotnet_style_qualification_for_property = false
+
+# Types: use keywords instead of BCL types, and permit var only when the type is clear
+csharp_style_var_for_built_in_types = false:suggestion
+csharp_style_var_when_type_is_apparent = false:none
+csharp_style_var_elsewhere = false:suggestion
+
+# Language keywords vs BCL types preferences
+dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
+dotnet_style_predefined_type_for_member_access = true:suggestion
+
+# Parentheses preferences
+dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity
+dotnet_style_parentheses_in_other_binary_operators = always_for_clarity
+dotnet_style_parentheses_in_other_operators = never_if_unnecessary
+dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity
+
+# Modifier preferences
+dotnet_style_require_accessibility_modifiers = for_non_interface_members
+
+# Expression-level preferences
+dotnet_style_coalesce_expression = true
+dotnet_style_collection_initializer = true
+dotnet_style_explicit_tuple_names = true
+dotnet_style_namespace_match_folder = true
+dotnet_style_null_propagation = true
+dotnet_style_object_initializer = true
+dotnet_style_operator_placement_when_wrapping = beginning_of_line
+dotnet_style_prefer_auto_properties = true
+dotnet_style_prefer_compound_assignment = true
+dotnet_style_prefer_conditional_expression_over_assignment = true
+dotnet_style_prefer_conditional_expression_over_return = true
+dotnet_style_prefer_inferred_anonymous_type_member_names = true
+dotnet_style_prefer_inferred_tuple_names = true
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true
+dotnet_style_prefer_simplified_boolean_expressions = true
+dotnet_style_prefer_simplified_interpolation = true
+
+# Field preferences
+dotnet_style_readonly_field = true
+
+# Parameter preferences
+dotnet_code_quality_unused_parameters = all
+
+# Suppression preferences
+dotnet_remove_unnecessary_suppression_exclusions = none
+
+# New line preferences
+dotnet_style_allow_multiple_blank_lines_experimental = true
+dotnet_style_allow_statement_immediately_after_block_experimental = true
+
+#### C# Coding Conventions ####
+
+# var preferences
+csharp_style_var_elsewhere = false:silent
+csharp_style_var_for_built_in_types = false:silent
+csharp_style_var_when_type_is_apparent = false:silent
+
+# Expression-bodied members
+csharp_style_expression_bodied_accessors = true:silent
+csharp_style_expression_bodied_constructors = false:silent
+csharp_style_expression_bodied_indexers = true:silent
+csharp_style_expression_bodied_lambdas = true:silent
+csharp_style_expression_bodied_local_functions = false:silent
+csharp_style_expression_bodied_methods = false:silent
+csharp_style_expression_bodied_operators = false:silent
+csharp_style_expression_bodied_properties = true:silent
+
+# Pattern matching preferences
+csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
+csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
+csharp_style_prefer_extended_property_pattern = true:suggestion
+csharp_style_prefer_not_pattern = true:suggestion
+csharp_style_prefer_pattern_matching = true:silent
+csharp_style_prefer_switch_expression = true:suggestion
+
+# Null-checking preferences
+csharp_style_conditional_delegate_call = true:suggestion
+
+# Modifier preferences
+csharp_prefer_static_local_function = true:suggestion
+csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async
+
+# Code-block preferences
+csharp_prefer_braces = true:silent
+csharp_prefer_simple_using_statement = true:suggestion
+csharp_style_namespace_declarations = block_scoped:silent
+
+# Expression-level preferences
+csharp_prefer_simple_default_expression = true:suggestion
+csharp_style_deconstructed_variable_declaration = true:suggestion
+csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
+csharp_style_inlined_variable_declaration = true:suggestion
+csharp_style_prefer_index_operator = true:suggestion
+csharp_style_prefer_local_over_anonymous_function = true:suggestion
+csharp_style_prefer_null_check_over_type_check = true:suggestion
+csharp_style_prefer_range_operator = true:suggestion
+csharp_style_prefer_tuple_swap = true:suggestion
+csharp_style_throw_expression = true:suggestion
+csharp_style_unused_value_assignment_preference = discard_variable:suggestion
+csharp_style_unused_value_expression_statement_preference = discard_variable:silent
+
+# 'using' directive preferences
+csharp_using_directive_placement = outside_namespace:silent
+
+# New line preferences
+csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent
+csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent
+csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent
+
+#### C# Formatting Rules ####
+
+# New line preferences
+csharp_new_line_before_catch = true
+csharp_new_line_before_else = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_members_in_anonymous_types = true
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_open_brace = all
+csharp_new_line_between_query_expression_clauses = true
+
+# Indentation preferences
+csharp_indent_block_contents = true
+csharp_indent_braces = false
+csharp_indent_case_contents = true
+csharp_indent_case_contents_when_block = true
+csharp_indent_labels = one_less_than_current
+csharp_indent_switch_labels = true
+
+# Space preferences
+csharp_space_after_cast = false
+csharp_space_after_colon_in_inheritance_clause = true
+csharp_space_after_comma = true
+csharp_space_after_dot = false
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_after_semicolon_in_for_statement = true
+csharp_space_around_binary_operators = before_and_after
+csharp_space_around_declaration_statements = false
+csharp_space_before_colon_in_inheritance_clause = true
+csharp_space_before_comma = false
+csharp_space_before_dot = false
+csharp_space_before_open_square_brackets = false
+csharp_space_before_semicolon_in_for_statement = false
+csharp_space_between_empty_square_brackets = false
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+csharp_space_between_method_call_parameter_list_parentheses = false
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+csharp_space_between_method_declaration_name_and_open_parenthesis = false
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+csharp_space_between_parentheses = false
+csharp_space_between_square_brackets = false
+
+# Wrapping preferences
+csharp_preserve_single_line_blocks = true:none
+csharp_preserve_single_line_statements = true:none
+
+#### Naming styles ####
+
+# Naming rules
+
+dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
+dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
+dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
+
+dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.types_should_be_pascal_case.symbols = types
+dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
+
+dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
+dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
+
+dotnet_naming_rule.private_or_internal_field_should_be__fieldname.severity = suggestion
+dotnet_naming_rule.private_or_internal_field_should_be__fieldname.symbols = private_or_internal_field
+dotnet_naming_rule.private_or_internal_field_should_be__fieldname.style = _fieldname
+
+# name all constant fields using PascalCase
+dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
+dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case
+dotnet_naming_symbols.constant_fields.applicable_kinds = field
+dotnet_naming_symbols.constant_fields.required_modifiers = const
+dotnet_naming_style.pascal_case_style.capitalization = pascal_case
+
+# Symbol specifications
+
+dotnet_naming_symbols.interface.applicable_kinds = interface
+dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.interface.required_modifiers =
+
+dotnet_naming_symbols.private_or_internal_field.applicable_kinds = field
+dotnet_naming_symbols.private_or_internal_field.applicable_accessibilities = internal, private, private_protected
+dotnet_naming_symbols.private_or_internal_field.required_modifiers =
+
+dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
+dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.types.required_modifiers =
+
+dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
+dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.non_field_members.required_modifiers =
+
+# Naming styles
+
+dotnet_naming_style.pascal_case.required_prefix =
+dotnet_naming_style.pascal_case.required_suffix =
+dotnet_naming_style.pascal_case.word_separator =
+dotnet_naming_style.pascal_case.capitalization = pascal_case
+
+dotnet_naming_style.begins_with_i.required_prefix = I
+dotnet_naming_style.begins_with_i.required_suffix =
+dotnet_naming_style.begins_with_i.word_separator =
+dotnet_naming_style.begins_with_i.capitalization = pascal_case
+
+dotnet_naming_style._fieldname.required_prefix = _
+dotnet_naming_style._fieldname.required_suffix =
+dotnet_naming_style._fieldname.word_separator =
+dotnet_naming_style._fieldname.capitalization = camel_case
+csharp_style_prefer_method_group_conversion = true:silent
+csharp_style_prefer_top_level_statements = true:silent
+csharp_style_prefer_utf8_string_literals = true:suggestion
+csharp_style_prefer_readonly_struct = true:suggestion
+csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true:silent
+csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true:silent
\ No newline at end of file
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000..dfe07704
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+# Auto detect text files and perform LF normalization
+* text=auto
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..d33d9275
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,404 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
+
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Mono auto generated files
+mono_crash.*
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Ww][Ii][Nn]32/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+[Ll]ogs/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# ASP.NET Scaffolding
+ScaffoldingReadMe.txt
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.tlog
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*.json
+coverage*.xml
+coverage*.info
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Nuget personal access tokens and Credentials
+nuget.config
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+.ionide/
+
+# Fody - auto-generated XML schema
+FodyWeavers.xsd
+
+# VS Code files for those working on multiple tools
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+*.code-workspace
+
+# Local History for Visual Studio Code
+.history/
+
+# Windows Installer files from build outputs
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+.vs/Wino/v16/.suo
+.vs/Wino/v16/.suo
+*.v2
+Wino/obj/x86/Debug/App.g.cs
+Wino/obj/x86/Debug/DesignTimeResolveAssemblyReferencesInput.cache
+Wino/obj/x86/Debug/XamlSaveStateFile.xml
+.vs/Wino/v16/.suo
+.vs/Wino/DesignTimeBuild/.dtbcache.v2
+.vs/Wino/v16/.suo
+*.v2
+Wino/obj/x86/Debug/XamlSaveStateFile.xml
+Wino/obj/x86/Debug/DesignTimeResolveAssemblyReferencesInput.cache
+Wino/obj/x86/Debug/XamlSaveStateFile.xml
+Wino/obj/x86/Debug/XamlSaveStateFile.xml
+*.cache
+.vs/Wino/v16/.suo
diff --git a/Wino.BackgroundTasks/AppUpdatedTask.cs b/Wino.BackgroundTasks/AppUpdatedTask.cs
new file mode 100644
index 00000000..2818a6a2
--- /dev/null
+++ b/Wino.BackgroundTasks/AppUpdatedTask.cs
@@ -0,0 +1,34 @@
+using Microsoft.Toolkit.Uwp.Notifications;
+using Windows.ApplicationModel;
+using Windows.ApplicationModel.Background;
+using Wino.Core.Domain;
+
+namespace Wino.BackgroundTasks
+{
+ ///
+ /// Creates a toast notification to notify user when the Store update happens.
+ ///
+ public sealed class AppUpdatedTask : IBackgroundTask
+ {
+ public void Run(IBackgroundTaskInstance taskInstance)
+ {
+ var def = taskInstance.GetDeferral();
+
+ var builder = new ToastContentBuilder();
+ builder.SetToastScenario(ToastScenario.Default);
+
+ Package package = Package.Current;
+ PackageId packageId = package.Id;
+ PackageVersion version = packageId.Version;
+
+ var versionText = string.Format("{0}.{1}.{2}.{3}", version.Major, version.Minor, version.Build, version.Revision);
+
+ builder.AddText(Translator.Notifications_WinoUpdatedTitle);
+ builder.AddText(string.Format(Translator.Notifications_WinoUpdatedMessage, versionText));
+
+ builder.Show();
+
+ def.Complete();
+ }
+ }
+}
diff --git a/Wino.BackgroundTasks/Properties/AssemblyInfo.cs b/Wino.BackgroundTasks/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..9887885d
--- /dev/null
+++ b/Wino.BackgroundTasks/Properties/AssemblyInfo.cs
@@ -0,0 +1,29 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Wino.BackgroundTasks")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Wino.BackgroundTasks")]
+[assembly: AssemblyCopyright("Copyright © 2023")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: ComVisible(false)]
\ No newline at end of file
diff --git a/Wino.BackgroundTasks/SessionConnectedTask.cs b/Wino.BackgroundTasks/SessionConnectedTask.cs
new file mode 100644
index 00000000..90db6769
--- /dev/null
+++ b/Wino.BackgroundTasks/SessionConnectedTask.cs
@@ -0,0 +1,48 @@
+using System;
+using Microsoft.Extensions.DependencyInjection;
+using Serilog;
+using Windows.ApplicationModel.Background;
+using Windows.Storage;
+using Wino.Core;
+using Wino.Core.Domain.Interfaces;
+using Wino.Core.Services;
+using Wino.Core.UWP;
+using Wino.Services;
+
+namespace Wino.BackgroundTasks
+{
+ public sealed class SessionConnectedTask : IBackgroundTask
+ {
+ public async void Run(IBackgroundTaskInstance taskInstance)
+ {
+ var def = taskInstance.GetDeferral();
+
+ try
+ {
+ var services = new ServiceCollection();
+
+ services.RegisterCoreServices();
+ services.RegisterCoreUWPServices();
+
+ var providere = services.BuildServiceProvider();
+
+ var backgroundTaskService = providere.GetService();
+ var dbService = providere.GetService();
+ var logInitializer = providere.GetService();
+
+ logInitializer.SetupLogger(ApplicationData.Current.LocalFolder.Path);
+
+ await dbService.InitializeAsync();
+ await backgroundTaskService.RunBackgroundSynchronizationAsync(Core.Domain.Enums.BackgroundSynchronizationReason.SessionConnected);
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex, "Background synchronization failed from background task.");
+ }
+ finally
+ {
+ def.Complete();
+ }
+ }
+ }
+}
diff --git a/Wino.BackgroundTasks/Wino.BackgroundTasks.csproj b/Wino.BackgroundTasks/Wino.BackgroundTasks.csproj
new file mode 100644
index 00000000..94ab7119
--- /dev/null
+++ b/Wino.BackgroundTasks/Wino.BackgroundTasks.csproj
@@ -0,0 +1,166 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {D9EF0F59-F5F2-4D6C-A5BA-84043D8F3E08}
+ winmdobj
+ Properties
+ Wino.BackgroundTasks
+ Wino.BackgroundTasks
+ en-US
+ UAP
+ 10.0.22621.0
+ 10.0.17763.0
+ 14
+ 512
+ {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ false
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ prompt
+ 4
+
+
+ x86
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ false
+ prompt
+
+
+ x86
+ bin\x86\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ false
+ prompt
+
+
+ ARM
+ true
+ bin\ARM\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ false
+ prompt
+
+
+ ARM
+ bin\ARM\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ false
+ prompt
+
+
+ ARM64
+ true
+ bin\ARM64\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ false
+ prompt
+
+
+ ARM64
+ bin\ARM64\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ false
+ prompt
+
+
+ x64
+ true
+ bin\x64\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ false
+ prompt
+
+
+ x64
+ bin\x64\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ false
+ prompt
+
+
+ PackageReference
+
+
+
+
+
+
+
+
+ 6.2.14
+
+
+ 7.1.3
+
+
+
+
+ {CF3312E5-5DA0-4867-9945-49EA7598AF1F}
+ Wino.Core.Domain
+
+
+ {395f19ba-1e42-495c-9db5-1a6f537fccb8}
+ Wino.Core.UWP
+
+
+ {e6b1632a-8901-41e8-9ddf-6793c7698b0b}
+ Wino.Core
+
+
+
+
+ Windows Desktop Extensions for the UWP
+
+
+
+ 14.0
+
+
+
+
\ No newline at end of file
diff --git a/Wino.Calendar/App.xaml b/Wino.Calendar/App.xaml
new file mode 100644
index 00000000..5707d1ac
--- /dev/null
+++ b/Wino.Calendar/App.xaml
@@ -0,0 +1,7 @@
+
+
+
diff --git a/Wino.Calendar/App.xaml.cs b/Wino.Calendar/App.xaml.cs
new file mode 100644
index 00000000..971e694b
--- /dev/null
+++ b/Wino.Calendar/App.xaml.cs
@@ -0,0 +1,100 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices.WindowsRuntime;
+using Windows.ApplicationModel;
+using Windows.ApplicationModel.Activation;
+using Windows.Foundation;
+using Windows.Foundation.Collections;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Controls.Primitives;
+using Windows.UI.Xaml.Data;
+using Windows.UI.Xaml.Input;
+using Windows.UI.Xaml.Media;
+using Windows.UI.Xaml.Navigation;
+
+namespace Wino.Calendar
+{
+ ///
+ /// Provides application-specific behavior to supplement the default Application class.
+ ///
+ sealed partial class App : Application
+ {
+ ///
+ /// Initializes the singleton application object. This is the first line of authored code
+ /// executed, and as such is the logical equivalent of main() or WinMain().
+ ///
+ public App()
+ {
+ this.InitializeComponent();
+ this.Suspending += OnSuspending;
+ }
+
+ ///
+ /// Invoked when the application is launched normally by the end user. Other entry points
+ /// will be used such as when the application is launched to open a specific file.
+ ///
+ /// Details about the launch request and process.
+ protected override void OnLaunched(LaunchActivatedEventArgs e)
+ {
+ Frame rootFrame = Window.Current.Content as Frame;
+
+ // Do not repeat app initialization when the Window already has content,
+ // just ensure that the window is active
+ if (rootFrame == null)
+ {
+ // Create a Frame to act as the navigation context and navigate to the first page
+ rootFrame = new Frame();
+
+ rootFrame.NavigationFailed += OnNavigationFailed;
+
+ if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
+ {
+ //TODO: Load state from previously suspended application
+ }
+
+ // Place the frame in the current Window
+ Window.Current.Content = rootFrame;
+ }
+
+ if (e.PrelaunchActivated == false)
+ {
+ if (rootFrame.Content == null)
+ {
+ // When the navigation stack isn't restored navigate to the first page,
+ // configuring the new page by passing required information as a navigation
+ // parameter
+ rootFrame.Navigate(typeof(MainPage), e.Arguments);
+ }
+ // Ensure the current window is active
+ Window.Current.Activate();
+ }
+ }
+
+ ///
+ /// Invoked when Navigation to a certain page fails
+ ///
+ /// The Frame which failed navigation
+ /// Details about the navigation failure
+ void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
+ {
+ throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
+ }
+
+ ///
+ /// Invoked when application execution is being suspended. Application state is saved
+ /// without knowing whether the application will be terminated or resumed with the contents
+ /// of memory still intact.
+ ///
+ /// The source of the suspend request.
+ /// Details about the suspend request.
+ private void OnSuspending(object sender, SuspendingEventArgs e)
+ {
+ var deferral = e.SuspendingOperation.GetDeferral();
+ //TODO: Save application state and stop any background activity
+ deferral.Complete();
+ }
+ }
+}
diff --git a/Wino.Calendar/Assets/LockScreenLogo.scale-200.png b/Wino.Calendar/Assets/LockScreenLogo.scale-200.png
new file mode 100644
index 00000000..735f57ad
Binary files /dev/null and b/Wino.Calendar/Assets/LockScreenLogo.scale-200.png differ
diff --git a/Wino.Calendar/Assets/SplashScreen.scale-200.png b/Wino.Calendar/Assets/SplashScreen.scale-200.png
new file mode 100644
index 00000000..023e7f1f
Binary files /dev/null and b/Wino.Calendar/Assets/SplashScreen.scale-200.png differ
diff --git a/Wino.Calendar/Assets/Square150x150Logo.scale-200.png b/Wino.Calendar/Assets/Square150x150Logo.scale-200.png
new file mode 100644
index 00000000..af49fec1
Binary files /dev/null and b/Wino.Calendar/Assets/Square150x150Logo.scale-200.png differ
diff --git a/Wino.Calendar/Assets/Square44x44Logo.scale-200.png b/Wino.Calendar/Assets/Square44x44Logo.scale-200.png
new file mode 100644
index 00000000..ce342a2e
Binary files /dev/null and b/Wino.Calendar/Assets/Square44x44Logo.scale-200.png differ
diff --git a/Wino.Calendar/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/Wino.Calendar/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
new file mode 100644
index 00000000..f6c02ce9
Binary files /dev/null and b/Wino.Calendar/Assets/Square44x44Logo.targetsize-24_altform-unplated.png differ
diff --git a/Wino.Calendar/Assets/StoreLogo.png b/Wino.Calendar/Assets/StoreLogo.png
new file mode 100644
index 00000000..7385b56c
Binary files /dev/null and b/Wino.Calendar/Assets/StoreLogo.png differ
diff --git a/Wino.Calendar/Assets/Wide310x150Logo.scale-200.png b/Wino.Calendar/Assets/Wide310x150Logo.scale-200.png
new file mode 100644
index 00000000..288995b3
Binary files /dev/null and b/Wino.Calendar/Assets/Wide310x150Logo.scale-200.png differ
diff --git a/Wino.Calendar/MainPage.xaml b/Wino.Calendar/MainPage.xaml
new file mode 100644
index 00000000..136e046c
--- /dev/null
+++ b/Wino.Calendar/MainPage.xaml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
diff --git a/Wino.Calendar/MainPage.xaml.cs b/Wino.Calendar/MainPage.xaml.cs
new file mode 100644
index 00000000..281f422f
--- /dev/null
+++ b/Wino.Calendar/MainPage.xaml.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices.WindowsRuntime;
+using Windows.Foundation;
+using Windows.Foundation.Collections;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Controls.Primitives;
+using Windows.UI.Xaml.Data;
+using Windows.UI.Xaml.Input;
+using Windows.UI.Xaml.Media;
+using Windows.UI.Xaml.Navigation;
+
+// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
+
+namespace Wino.Calendar
+{
+ ///
+ /// An empty page that can be used on its own or navigated to within a Frame.
+ ///
+ public sealed partial class MainPage : Page
+ {
+ public MainPage()
+ {
+ this.InitializeComponent();
+ }
+ }
+}
diff --git a/Wino.Calendar/Package.appxmanifest b/Wino.Calendar/Package.appxmanifest
new file mode 100644
index 00000000..6e261c84
--- /dev/null
+++ b/Wino.Calendar/Package.appxmanifest
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Wino Calendar
+ Burak KÖSE
+ Assets\StoreLogo.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Wino.Calendar/Properties/AssemblyInfo.cs b/Wino.Calendar/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..979badd3
--- /dev/null
+++ b/Wino.Calendar/Properties/AssemblyInfo.cs
@@ -0,0 +1,29 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Wino.Calendar")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Wino.Calendar")]
+[assembly: AssemblyCopyright("Copyright © 2023")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: ComVisible(false)]
\ No newline at end of file
diff --git a/Wino.Calendar/Properties/Default.rd.xml b/Wino.Calendar/Properties/Default.rd.xml
new file mode 100644
index 00000000..af00722c
--- /dev/null
+++ b/Wino.Calendar/Properties/Default.rd.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Wino.Calendar/Wino.Calendar.csproj b/Wino.Calendar/Wino.Calendar.csproj
new file mode 100644
index 00000000..2a0e6530
--- /dev/null
+++ b/Wino.Calendar/Wino.Calendar.csproj
@@ -0,0 +1,172 @@
+
+
+
+
+ Debug
+ x86
+ {600F4979-DB7E-409D-B7DA-B60BE4C55C35}
+ AppContainerExe
+ Properties
+ Wino.Calendar
+ Wino.Calendar
+ en-US
+ UAP
+ 10.0.22621.0
+ 10.0.17763.0
+ 14
+ 512
+ {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ true
+ True
+ 125A5273FCFE8D551C3FED87F67C87A663E98F1B
+
+ True
+
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ x86
+ false
+ prompt
+ true
+
+
+ bin\x86\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ x86
+ false
+ prompt
+ true
+ true
+
+
+ true
+ bin\ARM\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ ARM
+ false
+ prompt
+ true
+
+
+ bin\ARM\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ ARM
+ false
+ prompt
+ true
+ true
+
+
+ true
+ bin\ARM64\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ ARM64
+ false
+ prompt
+ true
+ true
+
+
+ bin\ARM64\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ ARM64
+ false
+ prompt
+ true
+ true
+
+
+ true
+ bin\x64\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ x64
+ false
+ prompt
+ true
+
+
+ bin\x64\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ x64
+ false
+ prompt
+ true
+ true
+
+
+ PackageReference
+
+
+
+ App.xaml
+
+
+ MainPage.xaml
+
+
+
+
+
+ Designer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MSBuild:Compile
+ Designer
+
+
+ MSBuild:Compile
+ Designer
+
+
+
+
+ 6.2.14
+
+
+
+ 14.0
+
+
+
+
\ No newline at end of file
diff --git a/Wino.Core.Domain/Constants.cs b/Wino.Core.Domain/Constants.cs
new file mode 100644
index 00000000..10046f85
--- /dev/null
+++ b/Wino.Core.Domain/Constants.cs
@@ -0,0 +1,14 @@
+namespace Wino.Core.Domain
+{
+ public static class Constants
+ {
+ ///
+ /// MIME header that exists in all the drafts created from Wino.
+ ///
+ public const string WinoLocalDraftHeader = "X-Wino-Draft-Id";
+ public const string LocalDraftStartPrefix = "localDraft_";
+
+ public const string ToastMailItemIdKey = nameof(ToastMailItemIdKey);
+ public const string ToastActionKey = nameof(ToastActionKey);
+ }
+}
diff --git a/Wino.Core.Domain/Entities/AccountSignature.cs b/Wino.Core.Domain/Entities/AccountSignature.cs
new file mode 100644
index 00000000..6c3c6841
--- /dev/null
+++ b/Wino.Core.Domain/Entities/AccountSignature.cs
@@ -0,0 +1,13 @@
+using System;
+using SQLite;
+
+namespace Wino.Core.Domain.Entities
+{
+ public class AccountSignature
+ {
+ [PrimaryKey]
+ public Guid Id { get; set; }
+
+ public string HtmlBody { get; set; }
+ }
+}
diff --git a/Wino.Core.Domain/Entities/AddressInformation.cs b/Wino.Core.Domain/Entities/AddressInformation.cs
new file mode 100644
index 00000000..de2bc308
--- /dev/null
+++ b/Wino.Core.Domain/Entities/AddressInformation.cs
@@ -0,0 +1,53 @@
+using SQLite;
+using System;
+using System.Collections.Generic;
+
+namespace Wino.Core.Domain.Entities
+{
+ ///
+ /// Back storage for simple name-address book.
+ /// These values will be inserted during MIME fetch.
+ ///
+
+
+ // TODO: This can easily evolve to Contact store, just like People app in Windows 10/11.
+ // Do it.
+ public class AddressInformation : IEquatable
+ {
+ [PrimaryKey]
+ public string Address { get; set; }
+ public string Name { get; set; }
+
+ public string DisplayName => Address == Name ? Address : $"{Name} <{Address}>";
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as AddressInformation);
+ }
+
+ public bool Equals(AddressInformation other)
+ {
+ return !(other is null) &&
+ Address == other.Address &&
+ Name == other.Name;
+ }
+
+ public override int GetHashCode()
+ {
+ int hashCode = -1717786383;
+ hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Address);
+ hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Name);
+ return hashCode;
+ }
+
+ public static bool operator ==(AddressInformation left, AddressInformation right)
+ {
+ return EqualityComparer.Default.Equals(left, right);
+ }
+
+ public static bool operator !=(AddressInformation left, AddressInformation right)
+ {
+ return !(left == right);
+ }
+ }
+}
diff --git a/Wino.Core.Domain/Entities/CustomServerInformation.cs b/Wino.Core.Domain/Entities/CustomServerInformation.cs
new file mode 100644
index 00000000..3fc99b76
--- /dev/null
+++ b/Wino.Core.Domain/Entities/CustomServerInformation.cs
@@ -0,0 +1,49 @@
+using System;
+using SQLite;
+using Wino.Core.Domain.Enums;
+
+namespace Wino.Core.Domain.Entities
+{
+ public class CustomServerInformation
+ {
+ [PrimaryKey]
+ public Guid Id { get; set; }
+
+ public Guid AccountId { get; set; }
+
+ public string DisplayName { get; set; }
+ public string Address { get; set; }
+ public string IncomingServer { get; set; }
+ public string IncomingServerUsername { get; set; }
+ public string IncomingServerPassword { get; set; }
+ public string IncomingServerPort { get; set; }
+
+ public CustomIncomingServerType IncomingServerType { get; set; }
+
+ public string OutgoingServer { get; set; }
+ public string OutgoingServerPort { get; set; }
+ public string OutgoingServerUsername { get; set; }
+ public string OutgoingServerPassword { get; set; }
+
+ ///
+ /// useSSL True: SslOnConnect
+ /// useSSL False: StartTlsWhenAvailable
+ ///
+
+ public ImapConnectionSecurity IncomingServerSocketOption { get; set; }
+ public ImapAuthenticationMethod IncomingAuthenticationMethod { get; set; }
+
+
+ public ImapConnectionSecurity OutgoingServerSocketOption { get; set; }
+ public ImapAuthenticationMethod OutgoingAuthenticationMethod { get; set; }
+
+ public string ProxyServer { get; set; }
+ public string ProxyServerPort { get; set; }
+
+ [Obsolete("As 1.7.0")]
+ public bool IncomingRequiresSSL { get; set; }
+
+ [Obsolete("As 1.7.0")]
+ public bool OutgoingRequresSSL { get; set; }
+ }
+}
diff --git a/Wino.Core.Domain/Entities/MailAccount.cs b/Wino.Core.Domain/Entities/MailAccount.cs
new file mode 100644
index 00000000..2ca32057
--- /dev/null
+++ b/Wino.Core.Domain/Entities/MailAccount.cs
@@ -0,0 +1,78 @@
+using System;
+using SQLite;
+using Wino.Core.Domain.Enums;
+
+namespace Wino.Core.Domain.Entities
+{
+ public class MailAccount
+ {
+ [PrimaryKey]
+ public Guid Id { get; set; }
+
+ ///
+ /// Given name of the account in Wino.
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// TODO: Display name of the authenticated user/account.
+ /// API integrations will query this value from the API.
+ /// IMAP is populated by user on setup dialog.
+ ///
+
+ public string ProfileName { get; set; }
+
+ ///
+ /// Account e-mail address.
+ ///
+ public string Address { get; set; }
+
+ ///
+ /// Provider type of the account. Outlook,Gmail etc...
+ ///
+ public MailProviderType ProviderType { get; set; }
+
+ ///
+ /// For tracking change delta.
+ /// Gmail : historyId
+ /// Outlook: deltaToken
+ ///
+ public string SynchronizationDeltaIdentifier { get; set; }
+
+ ///
+ /// Gets or sets the signature to be used for this account.
+ /// Null if no signature should be used.
+ ///
+ public Guid? SignatureId { get; set; }
+
+ ///
+ /// Gets or sets whether the account has any reason for an interactive user action to fix continue operating.
+ ///
+ public AccountAttentionReason AttentionReason { get; set; }
+
+ ///
+ /// Gets or sets the id of the merged inbox this account belongs to.
+ ///
+ public Guid? MergedInboxId { get; set; }
+
+ ///
+ /// Contains the merged inbox this account belongs to.
+ /// Ignored for all SQLite operations.
+ ///
+ [Ignore]
+ public MergedInbox MergedInbox { get; set; }
+
+ ///
+ /// Populated only when account has custom server information.
+ ///
+
+ [Ignore]
+ public CustomServerInformation ServerInformation { get; set; }
+
+ ///
+ /// Account preferences.
+ ///
+ [Ignore]
+ public MailAccountPreferences Preferences { get; set; }
+ }
+}
diff --git a/Wino.Core.Domain/Entities/MailAccountPreferences.cs b/Wino.Core.Domain/Entities/MailAccountPreferences.cs
new file mode 100644
index 00000000..3bcd23cd
--- /dev/null
+++ b/Wino.Core.Domain/Entities/MailAccountPreferences.cs
@@ -0,0 +1,39 @@
+using System;
+using SQLite;
+
+namespace Wino.Core.Domain.Entities
+{
+ public class MailAccountPreferences
+ {
+ [PrimaryKey]
+ public Guid Id { get; set; }
+
+ ///
+ /// Id of the account in MailAccount table.
+ ///
+ public Guid AccountId { get; set; }
+
+ ///
+ /// Gets or sets whether sent draft messages should be appended to the sent folder.
+ /// Some IMAP servers do this automatically, some don't.
+ /// It's disabled by default.
+ ///
+ public bool ShouldAppendMessagesToSentFolder { get; set; }
+
+ ///
+ /// Gets or sets whether the notifications are enabled for the account.
+ ///
+ public bool IsNotificationsEnabled { get; set; }
+
+ ///
+ /// Gets or sets the custom account identifier color in hex.
+ ///
+ public string AccountColorHex { get; set; }
+
+ ///
+ /// Gets or sets whether the account has Focused inbox support.
+ /// Null if the account provider type doesn't support Focused inbox.
+ ///
+ public bool? IsFocusedInboxEnabled { get; set; }
+ }
+}
diff --git a/Wino.Core.Domain/Entities/MailCopy.cs b/Wino.Core.Domain/Entities/MailCopy.cs
new file mode 100644
index 00000000..de56aa79
--- /dev/null
+++ b/Wino.Core.Domain/Entities/MailCopy.cs
@@ -0,0 +1,140 @@
+using System;
+using SQLite;
+using Wino.Core.Domain.Enums;
+using Wino.Core.Domain.Models.MailItem;
+
+namespace Wino.Core.Domain.Entities
+{
+ ///
+ /// Summary of the parsed MIME messages.
+ /// Wino will do non-network operations on this table and others from the original MIME.
+ ///
+ public class MailCopy : IMailItem
+ {
+ ///
+ /// Unique Id of the mail.
+ ///
+ [PrimaryKey]
+ public Guid UniqueId { get; set; }
+
+ ///
+ /// Not unique id of the item. Some operations held on this Id, some on the UniqueId.
+ /// Same message can be in different folder. In that case UniqueId is used.
+ ///
+ public string Id { get; set; }
+
+ ///
+ /// Folder that this mail belongs to.
+ ///
+ public Guid FolderId { get; set; }
+
+ ///
+ /// Conversation id for the mail.
+ ///
+ public string ThreadId { get; set; }
+
+ ///
+ /// MIME MessageId if exists.
+ ///
+ public string MessageId { get; set; }
+
+ ///
+ /// References header from MIME
+ ///
+ public string References { get; set; }
+
+ ///
+ /// In-Reply-To header from MIME
+ ///
+ public string InReplyTo { get; set; }
+
+ ///
+ /// Name for the sender.
+ ///
+ public string FromName { get; set; }
+
+ ///
+ /// Address of the sender.
+ ///
+ public string FromAddress { get; set; }
+
+ ///
+ /// Subject of the mail.
+ ///
+ public string Subject { get; set; }
+
+ ///
+ /// Short preview of the content.
+ ///
+ public string PreviewText { get; set; }
+
+ ///
+ /// Date that represents this mail has been created in provider servers.
+ /// Stored always in UTC.
+ ///
+ public DateTime CreationDate { get; set; }
+
+ ///
+ /// Importance of the mail.
+ ///
+ public MailImportance Importance { get; set; }
+
+ ///
+ /// Read status for the mail.
+ ///
+ public bool IsRead { get; set; }
+
+ ///
+ /// Flag status.
+ /// Flagged for Outlook.
+ /// Important for Gmail.
+ ///
+ public bool IsFlagged { get; set; }
+
+ ///
+ /// To support Outlook.
+ /// Gmail doesn't use it.
+ ///
+ public bool IsFocused { get; set; }
+
+ ///
+ /// Whether mail has attachments included or not.
+ ///
+ public bool HasAttachments { get; set; }
+
+ ///
+ /// Assigned draft id.
+ ///
+ public string DraftId { get; set; }
+
+ ///
+ /// Whether this copy is draft or not.
+ ///
+ public bool IsDraft { get; set; }
+
+ ///
+ /// File id that this mail is assigned to.
+ /// This Id is immutable. It's used to find the file in the file system.
+ /// Even after mapping local draft to remote draft, it will not change.
+ ///
+ public Guid FileId { get; set; }
+
+ ///
+ /// Folder that this mail is assigned to.
+ /// Warning: This field is not populated by queries.
+ /// Services or View Models are responsible for populating this field.
+ ///
+ [Ignore]
+ public MailItemFolder AssignedFolder { get; set; }
+
+ ///
+ /// Account that this mail is assigned to.
+ /// Warning: This field is not populated by queries.
+ /// Services or View Models are responsible for populating this field.
+ ///
+ [Ignore]
+ public MailAccount AssignedAccount { get; set; }
+
+ public override string ToString() => $"{Subject} <-> {Id}";
+ }
+}
diff --git a/Wino.Core.Domain/Entities/MailItemFolder.cs b/Wino.Core.Domain/Entities/MailItemFolder.cs
new file mode 100644
index 00000000..d33fbb15
--- /dev/null
+++ b/Wino.Core.Domain/Entities/MailItemFolder.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using SQLite;
+using Wino.Core.Domain.Enums;
+using Wino.Core.Domain.Models.Folders;
+
+namespace Wino.Core.Domain.Entities
+{
+ [DebuggerDisplay("{FolderName} - {SpecialFolderType}")]
+ public class MailItemFolder : IMailItemFolder
+ {
+ [PrimaryKey]
+ public Guid Id { get; set; }
+
+ public string RemoteFolderId { get; set; }
+ public string ParentRemoteFolderId { get; set; }
+
+ public Guid MailAccountId { get; set; }
+ public string FolderName { get; set; }
+ public SpecialFolderType SpecialFolderType { get; set; }
+ public bool IsSystemFolder { get; set; }
+ public bool IsSticky { get; set; }
+ public bool IsSynchronizationEnabled { get; set; }
+ public bool IsHidden { get; set; }
+ public bool ShowUnreadCount { get; set; }
+ public DateTime? LastSynchronizedDate { get; set; }
+
+ // For IMAP
+ public uint UidValidity { get; set; }
+ public long HighestModeSeq { get; set; }
+
+ ///
+ /// Outlook shares delta changes per-folder. Gmail is for per-account.
+ /// This is only used for Outlook provider.
+ ///
+ public string DeltaToken { get; set; }
+
+ // For GMail Labels
+ public string TextColorHex { get; set; }
+ public string BackgroundColorHex { get; set; }
+
+ [Ignore]
+ public List ChildFolders { get; set; } = [];
+
+ // Category and Move type folders are not valid move targets.
+ // These folders are virtual. They don't exist on the server.
+ public bool IsMoveTarget => !(SpecialFolderType == SpecialFolderType.More || SpecialFolderType == SpecialFolderType.Category);
+
+ public bool ContainsSpecialFolderType(SpecialFolderType type)
+ {
+ if (SpecialFolderType == type)
+ return true;
+
+ foreach (var child in ChildFolders)
+ {
+ if (child.SpecialFolderType == type)
+ {
+ return true;
+ }
+ else
+ {
+ return child.ContainsSpecialFolderType(type);
+ }
+ }
+
+ return false;
+ }
+
+ public override string ToString() => FolderName;
+ }
+}
diff --git a/Wino.Core.Domain/Entities/MergedInbox.cs b/Wino.Core.Domain/Entities/MergedInbox.cs
new file mode 100644
index 00000000..b9d0a58a
--- /dev/null
+++ b/Wino.Core.Domain/Entities/MergedInbox.cs
@@ -0,0 +1,13 @@
+using System;
+using SQLite;
+
+namespace Wino.Core.Domain.Entities
+{
+ public class MergedInbox
+ {
+ [PrimaryKey]
+ public Guid Id { get; set; }
+
+ public string Name { get; set; }
+ }
+}
diff --git a/Wino.Core.Domain/Entities/SystemFolderConfiguration.cs b/Wino.Core.Domain/Entities/SystemFolderConfiguration.cs
new file mode 100644
index 00000000..b4c532d1
--- /dev/null
+++ b/Wino.Core.Domain/Entities/SystemFolderConfiguration.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Wino.Core.Domain.Entities
+{
+ public record SystemFolderConfiguration(MailItemFolder SentFolder,
+ MailItemFolder DraftFolder,
+ MailItemFolder ArchiveFolder,
+ MailItemFolder TrashFolder,
+ MailItemFolder JunkFolder);
+}
diff --git a/Wino.Core.Domain/Entities/TokenInformation.cs b/Wino.Core.Domain/Entities/TokenInformation.cs
new file mode 100644
index 00000000..88bf292c
--- /dev/null
+++ b/Wino.Core.Domain/Entities/TokenInformation.cs
@@ -0,0 +1,26 @@
+using System;
+using SQLite;
+using Wino.Core.Domain.Models.Authentication;
+
+namespace Wino.Core.Domain.Entities
+{
+ public class TokenInformation : TokenInformationBase
+ {
+ [PrimaryKey]
+ public Guid Id { get; set; }
+
+ public Guid AccountId { get; set; }
+
+ public string Address { get; set; }
+
+ public void RefreshTokens(TokenInformationBase tokenInformationBase)
+ {
+ if (tokenInformationBase == null)
+ throw new ArgumentNullException(nameof(tokenInformationBase));
+
+ AccessToken = tokenInformationBase.AccessToken;
+ RefreshToken = tokenInformationBase.RefreshToken;
+ ExpiresAt = tokenInformationBase.ExpiresAt;
+ }
+ }
+}
diff --git a/Wino.Core.Domain/Enums/AccountAttentionReason.cs b/Wino.Core.Domain/Enums/AccountAttentionReason.cs
new file mode 100644
index 00000000..b192e74f
--- /dev/null
+++ b/Wino.Core.Domain/Enums/AccountAttentionReason.cs
@@ -0,0 +1,9 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum AccountAttentionReason
+ {
+ None,
+ InvalidCredentials,
+ MissingSystemFolderConfiguration
+ }
+}
diff --git a/Wino.Core.Domain/Enums/AccountCreationDialogState.cs b/Wino.Core.Domain/Enums/AccountCreationDialogState.cs
new file mode 100644
index 00000000..af724f47
--- /dev/null
+++ b/Wino.Core.Domain/Enums/AccountCreationDialogState.cs
@@ -0,0 +1,14 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum AccountCreationDialogState
+ {
+ Idle,
+ SigningIn,
+ PreparingFolders,
+ Completed,
+ ManuelSetupWaiting,
+ TestingConnection,
+ AutoDiscoverySetup,
+ AutoDiscoveryInProgress
+ }
+}
diff --git a/Wino.Core.Domain/Enums/AccountSynchronizerState.cs b/Wino.Core.Domain/Enums/AccountSynchronizerState.cs
new file mode 100644
index 00000000..9a9e0810
--- /dev/null
+++ b/Wino.Core.Domain/Enums/AccountSynchronizerState.cs
@@ -0,0 +1,12 @@
+namespace Wino.Core.Domain.Enums
+{
+ ///
+ /// Indicates the state of synchronizer.
+ ///
+ public enum AccountSynchronizerState
+ {
+ Idle,
+ ExecutingRequests,
+ Synchronizing
+ }
+}
diff --git a/Wino.Core.Domain/Enums/AppLanguage.cs b/Wino.Core.Domain/Enums/AppLanguage.cs
new file mode 100644
index 00000000..0f3a6b9f
--- /dev/null
+++ b/Wino.Core.Domain/Enums/AppLanguage.cs
@@ -0,0 +1,16 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum AppLanguage
+ {
+ None,
+ English,
+ Deutsch,
+ Russian,
+ Turkish,
+ Polish,
+ Czech,
+ Chinese,
+ Spanish,
+ French
+ }
+}
diff --git a/Wino.Core.Domain/Enums/AppThemeType.cs b/Wino.Core.Domain/Enums/AppThemeType.cs
new file mode 100644
index 00000000..138f499b
--- /dev/null
+++ b/Wino.Core.Domain/Enums/AppThemeType.cs
@@ -0,0 +1,9 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum AppThemeType
+ {
+ System,
+ PreDefined,
+ Custom,
+ }
+}
diff --git a/Wino.Core.Domain/Enums/ApplicationElementTheme.cs b/Wino.Core.Domain/Enums/ApplicationElementTheme.cs
new file mode 100644
index 00000000..6c3e0bca
--- /dev/null
+++ b/Wino.Core.Domain/Enums/ApplicationElementTheme.cs
@@ -0,0 +1,9 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum ApplicationElementTheme
+ {
+ Default,
+ Light,
+ Dark
+ }
+}
diff --git a/Wino.Core.Domain/Enums/BackgroundSynchronizationReason.cs b/Wino.Core.Domain/Enums/BackgroundSynchronizationReason.cs
new file mode 100644
index 00000000..eac0a746
--- /dev/null
+++ b/Wino.Core.Domain/Enums/BackgroundSynchronizationReason.cs
@@ -0,0 +1,8 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum BackgroundSynchronizationReason
+ {
+ SessionConnected,
+ Timer
+ }
+}
diff --git a/Wino.Core.Domain/Enums/ChangeRequestType.cs b/Wino.Core.Domain/Enums/ChangeRequestType.cs
new file mode 100644
index 00000000..d0af1669
--- /dev/null
+++ b/Wino.Core.Domain/Enums/ChangeRequestType.cs
@@ -0,0 +1,24 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum ChangeRequestType
+ {
+ MailMarkAs,
+ MailChangeFlag,
+ MailHardDelete,
+ MailMove,
+ MailAlwaysMoveTo,
+ MailChangeFocused,
+ MailArchive,
+ MailUnarchive,
+ FolderMarkAsRead,
+ FolderDelete,
+ FolderEmpty,
+ FolderRename,
+ CreateNewDraft,
+ CreateReplyDraft,
+ CreateForwardDraft,
+ DiscardDraft,
+ SendDraft,
+ FetchSingleItem
+ }
+}
diff --git a/Wino.Core.Domain/Enums/CustomIncomingServerType.cs b/Wino.Core.Domain/Enums/CustomIncomingServerType.cs
new file mode 100644
index 00000000..40312e4a
--- /dev/null
+++ b/Wino.Core.Domain/Enums/CustomIncomingServerType.cs
@@ -0,0 +1,8 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum CustomIncomingServerType
+ {
+ POP3,
+ IMAP4
+ }
+}
diff --git a/Wino.Core.Domain/Enums/DraftCreationReason.cs b/Wino.Core.Domain/Enums/DraftCreationReason.cs
new file mode 100644
index 00000000..e988c03a
--- /dev/null
+++ b/Wino.Core.Domain/Enums/DraftCreationReason.cs
@@ -0,0 +1,10 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum DraftCreationReason
+ {
+ Empty,
+ Reply,
+ ReplyAll,
+ Forward
+ }
+}
diff --git a/Wino.Core.Domain/Enums/EditorToolbarSectionType.cs b/Wino.Core.Domain/Enums/EditorToolbarSectionType.cs
new file mode 100644
index 00000000..187c8cb2
--- /dev/null
+++ b/Wino.Core.Domain/Enums/EditorToolbarSectionType.cs
@@ -0,0 +1,11 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum EditorToolbarSectionType
+ {
+ None,
+ Format,
+ Insert,
+ Draw,
+ Options
+ }
+}
diff --git a/Wino.Core.Domain/Enums/FilterOptionType.cs b/Wino.Core.Domain/Enums/FilterOptionType.cs
new file mode 100644
index 00000000..4882f76b
--- /dev/null
+++ b/Wino.Core.Domain/Enums/FilterOptionType.cs
@@ -0,0 +1,10 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum FilterOptionType
+ {
+ All,
+ Unread,
+ Flagged,
+ Mentions
+ }
+}
diff --git a/Wino.Core.Domain/Enums/FolderOperation.cs b/Wino.Core.Domain/Enums/FolderOperation.cs
new file mode 100644
index 00000000..2d33144f
--- /dev/null
+++ b/Wino.Core.Domain/Enums/FolderOperation.cs
@@ -0,0 +1,23 @@
+namespace Wino.Core.Domain.Enums
+{
+ ///
+ /// Defines all possible folder operations that can be done.
+ /// Available values for each folder is returned by IContextMenuProvider
+ /// that integrators hold.
+ ///
+ public enum FolderOperation
+ {
+ None,
+ Pin,
+ Unpin,
+ MarkAllAsRead,
+ DontSync,
+ Empty,
+ Rename,
+ Delete,
+ Move,
+ TurnOffNotifications,
+ CreateSubFolder,
+ Seperator
+ }
+}
diff --git a/Wino.Core.Domain/Enums/ImapAuthenticationMethod.cs b/Wino.Core.Domain/Enums/ImapAuthenticationMethod.cs
new file mode 100644
index 00000000..4390f247
--- /dev/null
+++ b/Wino.Core.Domain/Enums/ImapAuthenticationMethod.cs
@@ -0,0 +1,13 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum ImapAuthenticationMethod
+ {
+ Auto,
+ None,
+ NormalPassword,
+ EncryptedPassword,
+ Ntlm,
+ CramMd5,
+ DigestMd5
+ }
+}
diff --git a/Wino.Core.Domain/Enums/ImapConnectionSecurity.cs b/Wino.Core.Domain/Enums/ImapConnectionSecurity.cs
new file mode 100644
index 00000000..9a3e6e7b
--- /dev/null
+++ b/Wino.Core.Domain/Enums/ImapConnectionSecurity.cs
@@ -0,0 +1,10 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum ImapConnectionSecurity
+ {
+ Auto,
+ None,
+ StartTls,
+ SslTls
+ }
+}
diff --git a/Wino.Core.Domain/Enums/InfoBarAnimationType.cs b/Wino.Core.Domain/Enums/InfoBarAnimationType.cs
new file mode 100644
index 00000000..488b667b
--- /dev/null
+++ b/Wino.Core.Domain/Enums/InfoBarAnimationType.cs
@@ -0,0 +1,8 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum InfoBarAnimationType
+ {
+ SlideFromRightToLeft,
+ SlideFromBottomToTop
+ }
+}
diff --git a/Wino.Core.Domain/Enums/InfoBarMessageType.cs b/Wino.Core.Domain/Enums/InfoBarMessageType.cs
new file mode 100644
index 00000000..15df6dcf
--- /dev/null
+++ b/Wino.Core.Domain/Enums/InfoBarMessageType.cs
@@ -0,0 +1,10 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum InfoBarMessageType
+ {
+ Information,
+ Success,
+ Warning,
+ Error
+ }
+}
diff --git a/Wino.Core.Domain/Enums/MailAttachmentType.cs b/Wino.Core.Domain/Enums/MailAttachmentType.cs
new file mode 100644
index 00000000..b444b4c5
--- /dev/null
+++ b/Wino.Core.Domain/Enums/MailAttachmentType.cs
@@ -0,0 +1,16 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum MailAttachmentType
+ {
+ None,
+ Executable,
+ Image,
+ Audio,
+ Video,
+ PDF,
+ HTML,
+ RarArchive,
+ Archive,
+ Other
+ }
+}
diff --git a/Wino.Core.Domain/Enums/MailImportance.cs b/Wino.Core.Domain/Enums/MailImportance.cs
new file mode 100644
index 00000000..22f2a6ab
--- /dev/null
+++ b/Wino.Core.Domain/Enums/MailImportance.cs
@@ -0,0 +1,9 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum MailImportance
+ {
+ Low,
+ Normal,
+ High
+ }
+}
diff --git a/Wino.Core.Domain/Enums/MailListDisplayMode.cs b/Wino.Core.Domain/Enums/MailListDisplayMode.cs
new file mode 100644
index 00000000..d27278e7
--- /dev/null
+++ b/Wino.Core.Domain/Enums/MailListDisplayMode.cs
@@ -0,0 +1,9 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum MailListDisplayMode
+ {
+ Spacious,
+ Medium,
+ Compact,
+ }
+}
diff --git a/Wino.Core.Domain/Enums/MailMarkAsOption.cs b/Wino.Core.Domain/Enums/MailMarkAsOption.cs
new file mode 100644
index 00000000..e08ce803
--- /dev/null
+++ b/Wino.Core.Domain/Enums/MailMarkAsOption.cs
@@ -0,0 +1,9 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum MailMarkAsOption
+ {
+ WhenSelected,
+ DontMark,
+ AfterDelay
+ }
+}
diff --git a/Wino.Core.Domain/Enums/MailOperation.cs b/Wino.Core.Domain/Enums/MailOperation.cs
new file mode 100644
index 00000000..d221a090
--- /dev/null
+++ b/Wino.Core.Domain/Enums/MailOperation.cs
@@ -0,0 +1,49 @@
+namespace Wino.Core.Domain.Enums
+{
+ // Synchronizer requests.
+ public enum MailSynchronizerOperation
+ {
+ MarkRead,
+ Move,
+ Delete, // Hard delete.
+ CreateDraft,
+ Send,
+ ChangeFlag,
+ AlwaysMoveTo,
+ MoveToFocused,
+ RenameFolder
+ }
+
+ // UI requests
+ public enum MailOperation
+ {
+ None,
+ Archive,
+ UnArchive,
+ SoftDelete,
+ HardDelete,
+ Move,
+ MoveToJunk,
+ MoveToFocused,
+ MoveToOther,
+ AlwaysMoveToOther,
+ AlwaysMoveToFocused,
+ SetFlag,
+ ClearFlag,
+ MarkAsRead,
+ MarkAsUnread,
+ MarkAsNotJunk,
+ Seperator,
+ Ignore,
+ Reply,
+ ReplyAll,
+ Zoom,
+ SaveAs,
+ Find,
+ Forward,
+ DarkEditor,
+ LightEditor,
+ Print,
+ Navigate // For toast activation
+ }
+}
diff --git a/Wino.Core.Domain/Enums/MailProviderType.cs b/Wino.Core.Domain/Enums/MailProviderType.cs
new file mode 100644
index 00000000..a9156f68
--- /dev/null
+++ b/Wino.Core.Domain/Enums/MailProviderType.cs
@@ -0,0 +1,11 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum MailProviderType
+ {
+ Outlook,
+ Gmail,
+ Office365,
+ Yahoo,
+ IMAP4
+ }
+}
diff --git a/Wino.Core.Domain/Enums/MenuPaneMode.cs b/Wino.Core.Domain/Enums/MenuPaneMode.cs
new file mode 100644
index 00000000..3d6e77b8
--- /dev/null
+++ b/Wino.Core.Domain/Enums/MenuPaneMode.cs
@@ -0,0 +1,8 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum MenuPaneMode
+ {
+ Visible,
+ Hidden
+ }
+}
diff --git a/Wino.Core.Domain/Enums/NavigationReferenceFrame.cs b/Wino.Core.Domain/Enums/NavigationReferenceFrame.cs
new file mode 100644
index 00000000..1d116fdb
--- /dev/null
+++ b/Wino.Core.Domain/Enums/NavigationReferenceFrame.cs
@@ -0,0 +1,8 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum NavigationReferenceFrame
+ {
+ ShellFrame,
+ RenderingFrame
+ }
+}
diff --git a/Wino.Core.Domain/Enums/PickFolderReason.cs b/Wino.Core.Domain/Enums/PickFolderReason.cs
new file mode 100644
index 00000000..99067066
--- /dev/null
+++ b/Wino.Core.Domain/Enums/PickFolderReason.cs
@@ -0,0 +1,12 @@
+namespace Wino.Core.Domain.Enums
+{
+ ///
+ /// Defines the potential reasons for picking folder in the folder picking dialog.
+ ///
+ public enum PickFolderReason
+ {
+ Move,
+ SpecialFolder,
+ Any
+ }
+}
diff --git a/Wino.Core.Domain/Enums/ReaderFont.cs b/Wino.Core.Domain/Enums/ReaderFont.cs
new file mode 100644
index 00000000..53c0e39a
--- /dev/null
+++ b/Wino.Core.Domain/Enums/ReaderFont.cs
@@ -0,0 +1,15 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum ReaderFont
+ {
+ Arial,
+ TimesNewRoman,
+ Verdana,
+ Tahoma,
+ CourierNew,
+ Georgia,
+ TrebuchetMS,
+ Calibri,
+ Helvetica
+ }
+}
diff --git a/Wino.Core.Domain/Enums/SortingOptionType.cs b/Wino.Core.Domain/Enums/SortingOptionType.cs
new file mode 100644
index 00000000..4a88d2fd
--- /dev/null
+++ b/Wino.Core.Domain/Enums/SortingOptionType.cs
@@ -0,0 +1,8 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum SortingOptionType
+ {
+ ReceiveDate,
+ Sender
+ }
+}
diff --git a/Wino.Core.Domain/Enums/SpecialFolderType.cs b/Wino.Core.Domain/Enums/SpecialFolderType.cs
new file mode 100644
index 00000000..b26ae4c3
--- /dev/null
+++ b/Wino.Core.Domain/Enums/SpecialFolderType.cs
@@ -0,0 +1,24 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum SpecialFolderType
+ {
+ Inbox,
+ Starred,
+ Important,
+ Sent,
+ Draft,
+ Archive,
+ Deleted,
+ Junk,
+ Chat,
+ Category,
+ Unread,
+ Forums,
+ Updates,
+ Personal,
+ Promotions,
+ Social,
+ Other,
+ More
+ }
+}
diff --git a/Wino.Core.Domain/Enums/StorePurchaseResult.cs b/Wino.Core.Domain/Enums/StorePurchaseResult.cs
new file mode 100644
index 00000000..8364b81a
--- /dev/null
+++ b/Wino.Core.Domain/Enums/StorePurchaseResult.cs
@@ -0,0 +1,19 @@
+namespace Wino.Core.Domain.Enums
+{
+ // From the SDK.
+ public enum StorePurchaseResult
+ {
+ //
+ // Summary:
+ // The purchase request succeeded.
+ Succeeded,
+ //
+ // Summary:
+ // The current user has already purchased the specified app or add-on.
+ AlreadyPurchased,
+ //
+ // Summary:
+ // The purchase request did not succeed.
+ NotPurchased,
+ }
+}
diff --git a/Wino.Core.Domain/Enums/SynchronizationCompletedState.cs b/Wino.Core.Domain/Enums/SynchronizationCompletedState.cs
new file mode 100644
index 00000000..b4376afe
--- /dev/null
+++ b/Wino.Core.Domain/Enums/SynchronizationCompletedState.cs
@@ -0,0 +1,9 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum SynchronizationCompletedState
+ {
+ Success, // All succeeded.
+ Canceled, // Canceled by user or HTTP call.
+ Failed // Exception.
+ }
+}
diff --git a/Wino.Core.Domain/Enums/SynchronizationType.cs b/Wino.Core.Domain/Enums/SynchronizationType.cs
new file mode 100644
index 00000000..c95b7d52
--- /dev/null
+++ b/Wino.Core.Domain/Enums/SynchronizationType.cs
@@ -0,0 +1,11 @@
+namespace Wino.Core.Domain.Enums
+{
+ public enum SynchronizationType
+ {
+ FoldersOnly, // Only synchronize folder metadata.
+ ExecuteRequests, // Run the queued requests, and then synchronize if needed.
+ Inbox, // Only Inbox
+ Custom, // Only sync folders that are specified in the options.
+ Full, // Synchronize everything
+ }
+}
diff --git a/Wino.Core.Domain/Enums/WinoPage.cs b/Wino.Core.Domain/Enums/WinoPage.cs
new file mode 100644
index 00000000..69fbd7fa
--- /dev/null
+++ b/Wino.Core.Domain/Enums/WinoPage.cs
@@ -0,0 +1,25 @@
+namespace Wino.Core.Domain.Enums
+{
+ ///
+ /// All registered views.
+ ///
+ public enum WinoPage
+ {
+ None,
+ IdlePage,
+ ComposePage,
+ SettingsPage,
+ MailRenderingPage,
+ WelcomePage,
+ AccountDetailsPage,
+ MergedAccountDetailsPage,
+ AccountManagementPage,
+ SignatureManagementPage,
+ AboutPage,
+ PersonalizationPage,
+ MessageListPage,
+ MailListPage,
+ ReadingPanePage,
+ SettingOptionsPage
+ }
+}
diff --git a/Wino.Core.Domain/Exceptions/AccountSetupCanceledException.cs b/Wino.Core.Domain/Exceptions/AccountSetupCanceledException.cs
new file mode 100644
index 00000000..03819076
--- /dev/null
+++ b/Wino.Core.Domain/Exceptions/AccountSetupCanceledException.cs
@@ -0,0 +1,7 @@
+namespace Wino.Core.Domain.Exceptions
+{
+ public class AccountSetupCanceledException : System.Exception
+ {
+
+ }
+}
diff --git a/Wino.Core.Domain/Exceptions/AuthenticationAttentionException.cs b/Wino.Core.Domain/Exceptions/AuthenticationAttentionException.cs
new file mode 100644
index 00000000..63b577f8
--- /dev/null
+++ b/Wino.Core.Domain/Exceptions/AuthenticationAttentionException.cs
@@ -0,0 +1,19 @@
+using System;
+using Wino.Core.Domain.Entities;
+
+namespace Wino.Core.Domain.Exceptions
+{
+ ///
+ /// Thrown when IAuthenticator requires user interaction to fix authentication issues.
+ /// It can be expired and can't restorable token, or some stuff that requires re-authentication.
+ ///
+ public class AuthenticationAttentionException : Exception
+ {
+ public AuthenticationAttentionException(MailAccount account)
+ {
+ Account = account;
+ }
+
+ public MailAccount Account { get; }
+ }
+}
diff --git a/Wino.Core.Domain/Exceptions/AuthenticationException.cs b/Wino.Core.Domain/Exceptions/AuthenticationException.cs
new file mode 100644
index 00000000..87e622df
--- /dev/null
+++ b/Wino.Core.Domain/Exceptions/AuthenticationException.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Wino.Core.Domain.Exceptions
+{
+ ///
+ /// All exceptions related to authentication.
+ ///
+ public class AuthenticationException : Exception
+ {
+ public AuthenticationException(string message) : base(message)
+ {
+ }
+
+ public AuthenticationException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+ }
+}
diff --git a/Wino.Core.Domain/Exceptions/BackgroundTaskExecutionRequestDeniedException.cs b/Wino.Core.Domain/Exceptions/BackgroundTaskExecutionRequestDeniedException.cs
new file mode 100644
index 00000000..532addbd
--- /dev/null
+++ b/Wino.Core.Domain/Exceptions/BackgroundTaskExecutionRequestDeniedException.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Wino.Core.Domain.Exceptions
+{
+ ///
+ /// An exception thrown when the background task execution policies are denied for some reason.
+ ///
+ public class BackgroundTaskExecutionRequestDeniedException : Exception { }
+}
diff --git a/Wino.Core.Domain/Exceptions/BackgroundTaskRegistrationFailedException.cs b/Wino.Core.Domain/Exceptions/BackgroundTaskRegistrationFailedException.cs
new file mode 100644
index 00000000..50d3d40d
--- /dev/null
+++ b/Wino.Core.Domain/Exceptions/BackgroundTaskRegistrationFailedException.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Wino.Core.Domain.Exceptions
+{
+ ///
+ /// An exception thrown when the background task registration is failed.
+ ///
+ public class BackgroundTaskRegistrationFailedException : Exception { }
+}
diff --git a/Wino.Core.Domain/Exceptions/ComposerMimeNotFoundException.cs b/Wino.Core.Domain/Exceptions/ComposerMimeNotFoundException.cs
new file mode 100644
index 00000000..2a82d580
--- /dev/null
+++ b/Wino.Core.Domain/Exceptions/ComposerMimeNotFoundException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Wino.Core.Domain.Exceptions
+{
+ ///
+ /// Thrown when composer cant find the mime to load.
+ ///
+ public class ComposerMimeNotFoundException : Exception
+ {
+ }
+}
diff --git a/Wino.Core.Domain/Exceptions/CustomThemeCreationFailedException.cs b/Wino.Core.Domain/Exceptions/CustomThemeCreationFailedException.cs
new file mode 100644
index 00000000..8ffd3992
--- /dev/null
+++ b/Wino.Core.Domain/Exceptions/CustomThemeCreationFailedException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Wino.Core.Domain.Exceptions
+{
+ public class CustomThemeCreationFailedException : Exception
+ {
+ public CustomThemeCreationFailedException(string message) : base(message)
+ {
+ }
+ }
+}
diff --git a/Wino.Core.Domain/Exceptions/GoogleAuthenticationException.cs b/Wino.Core.Domain/Exceptions/GoogleAuthenticationException.cs
new file mode 100644
index 00000000..71d244c1
--- /dev/null
+++ b/Wino.Core.Domain/Exceptions/GoogleAuthenticationException.cs
@@ -0,0 +1,7 @@
+namespace Wino.Core.Domain.Exceptions
+{
+ public class GoogleAuthenticationException : System.Exception
+ {
+ public GoogleAuthenticationException(string message) : base(message) { }
+ }
+}
diff --git a/Wino.Core.Domain/Exceptions/ImapClientPoolException.cs b/Wino.Core.Domain/Exceptions/ImapClientPoolException.cs
new file mode 100644
index 00000000..bd027024
--- /dev/null
+++ b/Wino.Core.Domain/Exceptions/ImapClientPoolException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Wino.Core.Domain.Exceptions
+{
+ public class ImapClientPoolException : Exception
+ {
+ public ImapClientPoolException(Exception innerException) : base(Translator.Exception_ImapClientPoolFailed, innerException)
+ {
+ }
+ }
+}
diff --git a/Wino.Core.Domain/Exceptions/InvalidMoveTargetException.cs b/Wino.Core.Domain/Exceptions/InvalidMoveTargetException.cs
new file mode 100644
index 00000000..05f3e7b4
--- /dev/null
+++ b/Wino.Core.Domain/Exceptions/InvalidMoveTargetException.cs
@@ -0,0 +1,6 @@
+using System;
+
+namespace Wino.Core.Domain.Exceptions
+{
+ public class InvalidMoveTargetException : Exception { }
+}
diff --git a/Wino.Core.Domain/Exceptions/SynchronizerEntityNotFoundException.cs b/Wino.Core.Domain/Exceptions/SynchronizerEntityNotFoundException.cs
new file mode 100644
index 00000000..4d35aad6
--- /dev/null
+++ b/Wino.Core.Domain/Exceptions/SynchronizerEntityNotFoundException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Wino.Core.Domain.Exceptions
+{
+ public class SynchronizerEntityNotFoundException : Exception
+ {
+ public SynchronizerEntityNotFoundException(string message) : base(message)
+ {
+ }
+ }
+}
diff --git a/Wino.Core.Domain/Exceptions/SynchronizerException.cs b/Wino.Core.Domain/Exceptions/SynchronizerException.cs
new file mode 100644
index 00000000..cd2960fb
--- /dev/null
+++ b/Wino.Core.Domain/Exceptions/SynchronizerException.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Wino.Core.Domain.Exceptions
+{
+ public class SynchronizerException : Exception
+ {
+ public SynchronizerException(string message) : base(message)
+ {
+ }
+
+ public SynchronizerException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+ }
+}
diff --git a/Wino.Core.Domain/Exceptions/SystemFolderConfigurationMissingException.cs b/Wino.Core.Domain/Exceptions/SystemFolderConfigurationMissingException.cs
new file mode 100644
index 00000000..918aa253
--- /dev/null
+++ b/Wino.Core.Domain/Exceptions/SystemFolderConfigurationMissingException.cs
@@ -0,0 +1,7 @@
+namespace Wino.Core.Domain.Exceptions
+{
+ ///
+ /// When IMAP account's system folder configuration setup is not done yet.
+ ///
+ public class SystemFolderConfigurationMissingException : System.Exception { }
+}
diff --git a/Wino.Core.Domain/Exceptions/UnavailableSpecialFolderException.cs b/Wino.Core.Domain/Exceptions/UnavailableSpecialFolderException.cs
new file mode 100644
index 00000000..9153cbaa
--- /dev/null
+++ b/Wino.Core.Domain/Exceptions/UnavailableSpecialFolderException.cs
@@ -0,0 +1,20 @@
+using System;
+using Wino.Core.Domain.Enums;
+
+namespace Wino.Core.Domain.Exceptions
+{
+ ///
+ /// Emitted when special folder is needed for an operation but it couldn't be found.
+ ///
+ public class UnavailableSpecialFolderException : Exception
+ {
+ public UnavailableSpecialFolderException(SpecialFolderType specialFolderType, Guid accountId)
+ {
+ SpecialFolderType = specialFolderType;
+ AccountId = accountId;
+ }
+
+ public SpecialFolderType SpecialFolderType { get; }
+ public Guid AccountId { get; set; }
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/AfterRequestExecutionSynchronizationInterfaces.cs b/Wino.Core.Domain/Interfaces/AfterRequestExecutionSynchronizationInterfaces.cs
new file mode 100644
index 00000000..b1784d08
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/AfterRequestExecutionSynchronizationInterfaces.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ ///
+ /// An interface that should force synchronizer to do synchronization for only given folder ids
+ /// after the execution is completed.
+ ///
+ public interface ICustomFolderSynchronizationRequest
+ {
+ ///
+ /// Which folders to sync after this operation?
+ ///
+ List SynchronizationFolderIds { get; }
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IAccountCreationDialog.cs b/Wino.Core.Domain/Interfaces/IAccountCreationDialog.cs
new file mode 100644
index 00000000..c74a8413
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IAccountCreationDialog.cs
@@ -0,0 +1,11 @@
+using Wino.Core.Domain.Enums;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IAccountCreationDialog
+ {
+ void ShowDialog();
+ void Complete();
+ AccountCreationDialogState State { get; set; }
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IAccountMenuItem.cs b/Wino.Core.Domain/Interfaces/IAccountMenuItem.cs
new file mode 100644
index 00000000..b3870e3e
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IAccountMenuItem.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+using Wino.Core.Domain.Entities;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IAccountMenuItem : IMenuItem
+ {
+ double SynchronizationProgress { get; set; }
+ int UnreadItemCount { get; set; }
+ IEnumerable HoldingAccounts { get; }
+ void UpdateAccount(MailAccount account);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IAccountPickerDialog.cs b/Wino.Core.Domain/Interfaces/IAccountPickerDialog.cs
new file mode 100644
index 00000000..a43bbc26
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IAccountPickerDialog.cs
@@ -0,0 +1,6 @@
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IAccountPickerDialog
+ {
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IAccountProviderDetailViewModel.cs b/Wino.Core.Domain/Interfaces/IAccountProviderDetailViewModel.cs
new file mode 100644
index 00000000..b535fea1
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IAccountProviderDetailViewModel.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IAccountProviderDetailViewModel
+ {
+ ///
+ /// Entity id that will help to identify the startup entity on launch.
+ ///
+ Guid StartupEntityId { get; }
+
+ ///
+ /// Name representation of the view model that will be used to identify the startup entity on launch.
+ ///
+ string StartupEntityTitle { get; }
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IAccountProviderDetails.cs b/Wino.Core.Domain/Interfaces/IAccountProviderDetails.cs
new file mode 100644
index 00000000..65d0d5b7
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IAccountProviderDetails.cs
@@ -0,0 +1,11 @@
+using Wino.Core.Domain.Entities;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IAccountProviderDetails
+ {
+ MailAccount Account { get; set; }
+ bool AutoExtend { get; set; }
+ IProviderDetail ProviderDetail { get; set; }
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IAccountService.cs b/Wino.Core.Domain/Interfaces/IAccountService.cs
new file mode 100644
index 00000000..99190af3
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IAccountService.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Wino.Core.Domain.Entities;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IAccountService
+ {
+ ///
+ /// Current IAuthenticator that should receive external authentication process to continue with.
+ /// For example: Google auth will launch a browser authentication. After it completes, this is the IAuthenticator
+ /// to continue process for token exchange.
+ ///
+ IAuthenticator ExternalAuthenticationAuthenticator { get; set; }
+
+ ///
+ /// Returns all local accounts.
+ ///
+ /// All local accounts
+ Task> GetAccountsAsync();
+
+ ///
+ /// Returns single MailAccount
+ ///
+ /// AccountId.
+ Task GetAccountAsync(Guid accountId);
+
+ ///
+ /// Deletes all information about the account, including token information.
+ ///
+ /// MailAccount to be removed
+ Task DeleteAccountAsync(MailAccount account);
+
+ ///
+ /// Returns the custom server information for the given account id.
+ ///
+ Task GetAccountCustomServerInformationAsync(Guid accountId);
+
+ ///
+ /// Updates the given account properties.
+ ///
+ Task UpdateAccountAsync(MailAccount account);
+
+ ///
+ /// Creates new account with the given server information if any.
+ /// Also sets the account as Startup account if there are no accounts.
+ ///
+ Task CreateAccountAsync(MailAccount account, TokenInformation tokenInformation, CustomServerInformation customServerInformation);
+
+ ///
+ /// Fixed authentication errors for account by forcing interactive login.
+ ///
+ Task FixTokenIssuesAsync(Guid accountId);
+
+ ///
+ /// Removed the attention from an account.
+ ///
+ /// Account id to remove from
+ Task ClearAccountAttentionAsync(Guid accountId);
+
+ ///
+ /// Updates the account synchronization identifier.
+ /// For example: Gmail uses this identifier to keep track of the last synchronization.
+ /// Update is ignored for Gmail if the new identifier is older than the current one.
+ ///
+ /// Identifier to update
+ /// Current account synchronization modifier.
+ Task UpdateSynchronizationIdentifierAsync(Guid accountId, string newIdentifier);
+
+ Task RenameMergedAccountAsync(Guid mergedInboxId, string newName);
+
+ Task CreateMergeAccountsAsync(MergedInbox mergedInbox, IEnumerable accountsToMerge);
+
+ Task UpdateMergedInboxAsync(Guid mergedInboxId, IEnumerable linkedAccountIds);
+
+ Task UnlinkMergedInboxAsync(Guid mergedInboxId);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IAppInitializerService.cs b/Wino.Core.Domain/Interfaces/IAppInitializerService.cs
new file mode 100644
index 00000000..ffc6945d
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IAppInitializerService.cs
@@ -0,0 +1,11 @@
+using System.Threading.Tasks;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IAppInitializerService
+ {
+ string GetApplicationDataFolder();
+
+ Task MigrateAsync();
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IApplicationResourceManager.cs b/Wino.Core.Domain/Interfaces/IApplicationResourceManager.cs
new file mode 100644
index 00000000..a8e1b22c
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IApplicationResourceManager.cs
@@ -0,0 +1,11 @@
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IApplicationResourceManager
+ {
+ void RemoveResource(T resource);
+ void AddResource(T resource);
+ bool ContainsResourceKey(string resourceKey);
+ void ReplaceResource(string resourceKey, object resource);
+ T GetLastResource();
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IAuthenticationProvider.cs b/Wino.Core.Domain/Interfaces/IAuthenticationProvider.cs
new file mode 100644
index 00000000..49390dcb
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IAuthenticationProvider.cs
@@ -0,0 +1,9 @@
+using Wino.Core.Domain.Enums;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IAuthenticationProvider
+ {
+ IAuthenticator GetAuthenticator(MailProviderType providerType);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IAuthenticator.cs b/Wino.Core.Domain/Interfaces/IAuthenticator.cs
new file mode 100644
index 00000000..ced495d6
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IAuthenticator.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Threading.Tasks;
+using Wino.Core.Domain.Entities;
+using Wino.Core.Domain.Enums;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IAuthenticator
+ {
+ ///
+ /// Type of the provider.
+ ///
+ MailProviderType ProviderType { get; }
+
+ ///
+ /// Gets the token from the cache if exists.
+ /// If the token is expired, tries to refresh.
+ /// This can throw AuthenticationAttentionException if silent refresh fails.
+ ///
+ /// Account to get token for.
+ /// Valid token info to be used in integrators.
+ Task GetTokenAsync(MailAccount account);
+
+ ///
+ /// Initial creation of token. Requires user interaction.
+ /// This will save token into database, but still returns for account creation
+ /// since account address is required.
+ ///
+ /// Token cache might ask for regeneration of token for specific
+ /// account address. If one is provided and re-generation native token doesn't belong to this address
+ /// token saving to database won't happen.
+ /// Freshly created TokenInformation..
+ Task GenerateTokenAsync(MailAccount account, bool saveToken);
+
+ ///
+ /// Required for external authorization on launched browser to continue.
+ /// Used for Gmail.
+ ///
+ /// Response's redirect uri.
+ void ContinueAuthorization(Uri authorizationResponseUri);
+
+ ///
+ /// For external browser required authentications.
+ /// Canceling Gmail authentication dialog etc.
+ ///
+ void CancelAuthorization();
+
+ ///
+ /// ClientId in case of needed for authorization/authentication.
+ ///
+ string ClientId { get; }
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IAutoDiscoveryService.cs b/Wino.Core.Domain/Interfaces/IAutoDiscoveryService.cs
new file mode 100644
index 00000000..6886022d
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IAutoDiscoveryService.cs
@@ -0,0 +1,18 @@
+using System.Threading.Tasks;
+using Wino.Core.Domain.Models.AutoDiscovery;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ ///
+ /// Searches for Auto Discovery settings for custom mail accounts.
+ ///
+ public interface IAutoDiscoveryService
+ {
+ ///
+ /// Tries to return the best mail server settings using different techniques.
+ ///
+ /// Address to search settings for.
+ /// CustomServerInformation with only settings applied.
+ Task GetAutoDiscoverySettings(AutoDiscoveryMinimalSettings autoDiscoveryMinimalSettings);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IBackgroundTaskService.cs b/Wino.Core.Domain/Interfaces/IBackgroundTaskService.cs
new file mode 100644
index 00000000..b6411b32
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IBackgroundTaskService.cs
@@ -0,0 +1,19 @@
+using System.Threading.Tasks;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IBackgroundTaskService
+ {
+ ///
+ /// Manages background task registrations, requests access if needed, checks the statusses of them etc.
+ ///
+ /// If the access request is denied for some reason.
+ /// If one of the requires background tasks are failed during registration.
+ Task HandleBackgroundTaskRegistrations();
+
+ ///
+ /// Unregisters all existing background tasks. Useful for migrations.
+ ///
+ void UnregisterAllBackgroundTask();
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IClipboardService.cs b/Wino.Core.Domain/Interfaces/IClipboardService.cs
new file mode 100644
index 00000000..f5bb4782
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IClipboardService.cs
@@ -0,0 +1,9 @@
+using System.Threading.Tasks;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IClipboardService
+ {
+ Task CopyClipboardAsync(string text);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IConfigurationService.cs b/Wino.Core.Domain/Interfaces/IConfigurationService.cs
new file mode 100644
index 00000000..c08c463c
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IConfigurationService.cs
@@ -0,0 +1,11 @@
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IConfigurationService
+ {
+ void Set(string key, object value);
+ T Get(string key, T defaultValue = default);
+
+ void SetRoaming(string key, object value);
+ T GetRoaming(string key, T defaultValue = default);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IConfirmationDialog.cs b/Wino.Core.Domain/Interfaces/IConfirmationDialog.cs
new file mode 100644
index 00000000..34630448
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IConfirmationDialog.cs
@@ -0,0 +1,9 @@
+using System.Threading.Tasks;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IConfirmationDialog
+ {
+ Task ShowDialogAsync(string title, string message, string approveButtonTitle);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IContextMenuItemService.cs b/Wino.Core.Domain/Interfaces/IContextMenuItemService.cs
new file mode 100644
index 00000000..06d91240
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IContextMenuItemService.cs
@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+using Wino.Core.Domain.Models.Folders;
+using Wino.Core.Domain.Models.MailItem;
+using Wino.Core.Domain.Models.Menus;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IContextMenuItemService
+ {
+ IEnumerable GetFolderContextMenuActions(IBaseFolderMenuItem folderInformation);
+ IEnumerable GetMailItemContextMenuActions(IEnumerable selectedMailItems);
+ IEnumerable GetMailItemRenderMenuActions(IMailItem mailItem, bool isDarkEditor);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IContextMenuProvider.cs b/Wino.Core.Domain/Interfaces/IContextMenuProvider.cs
new file mode 100644
index 00000000..968b2c2c
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IContextMenuProvider.cs
@@ -0,0 +1,30 @@
+using System.Collections.Generic;
+using Wino.Core.Domain.Models.Folders;
+using Wino.Core.Domain.Models.MailItem;
+using Wino.Core.Domain.Models.Menus;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IContextMenuProvider
+ {
+ ///
+ /// Calculates and returns available folder operations for the given folder.
+ ///
+ /// Folder to get actions for.
+ IEnumerable GetFolderContextMenuActions(IMailItemFolder folderInformation);
+
+ ///
+ /// Calculates and returns available context menu items for selected mail items.
+ ///
+ /// Current folder that asks for the menu items.
+ /// Selected menu items in the given folder.
+ IEnumerable GetMailItemContextMenuActions(IMailItemFolder folderInformation, IEnumerable selectedMailItems);
+
+ ///
+ /// Calculates and returns available mail operations for mail rendering CommandBar.
+ ///
+ /// Rendered mail item.
+ /// Folder that mail item belongs to.
+ IEnumerable GetMailItemRenderMenuActions(IMailItem mailItem, IMailItemFolder activeFolder, bool isDarkEditor);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/ICustomServerAccountCreationDialog.cs b/Wino.Core.Domain/Interfaces/ICustomServerAccountCreationDialog.cs
new file mode 100644
index 00000000..ef3a81f1
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/ICustomServerAccountCreationDialog.cs
@@ -0,0 +1,19 @@
+using System.Threading.Tasks;
+using Wino.Core.Domain.Entities;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface ICustomServerAccountCreationDialog : IAccountCreationDialog
+ {
+ ///
+ /// Returns the custom server information from the dialog..
+ ///
+ /// Null if canceled.
+ Task GetCustomServerInformationAsync();
+
+ ///
+ /// Displays preparing folders page.
+ ///
+ void ShowPreparingFolders();
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IDialogService.cs b/Wino.Core.Domain/Interfaces/IDialogService.cs
new file mode 100644
index 00000000..d1954e9c
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IDialogService.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Wino.Core.Domain.Entities;
+using Wino.Core.Domain.Enums;
+using Wino.Core.Domain.Models.Folders;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IDialogService
+ {
+ Task PickWindowsFolderAsync();
+ Task PickWindowsFileContentAsync(params object[] typeFilters);
+ Task ShowConfirmationDialogAsync(string question, string title, string confirmationButtonTitle);
+ Task ShowHardDeleteConfirmationAsync();
+ Task ShowRatingDialogAsync();
+ Task HandleSystemFolderConfigurationDialogAsync(Guid accountId, IFolderService folderService);
+ Task ShowCustomThemeBuilderDialogAsync();
+
+ Task ShowMessageAsync(string message, string title);
+ void InfoBarMessage(string title, string message, InfoBarMessageType messageType);
+ void InfoBarMessage(string title, string message, InfoBarMessageType messageType, string actionButtonText, Action action);
+
+ void ShowNotSupportedMessage();
+
+ // Custom dialogs
+ Task ShowMoveMailFolderDialogAsync(List availableFolders);
+ Task> ShowNewAccountMailProviderDialogAsync(List availableProviders);
+ IAccountCreationDialog GetAccountCreationDialog(MailProviderType type);
+ Task ShowTextInputDialogAsync(string currentInput, string dialogTitle, string dialogDescription);
+ Task ShowEditAccountDialogAsync(MailAccount account);
+ Task ShowAccountPickerDialogAsync(List availableAccounts);
+
+ ///
+ /// Presents a dialog to the user for selecting folder.
+ ///
+ /// Account to get folders for.
+ /// The reason behind the picking operation
+ /// Selected folder structure. Null if none.
+ Task PickFolderAsync(Guid accountId, PickFolderReason reason, IFolderService folderService);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IDispatcher.cs b/Wino.Core.Domain/Interfaces/IDispatcher.cs
new file mode 100644
index 00000000..0eb9f08b
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IDispatcher.cs
@@ -0,0 +1,10 @@
+using System;
+using System.Threading.Tasks;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IDispatcher
+ {
+ Task ExecuteOnUIThread(Action action);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IFileService.cs b/Wino.Core.Domain/Interfaces/IFileService.cs
new file mode 100644
index 00000000..5500e2f9
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IFileService.cs
@@ -0,0 +1,12 @@
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IFileService
+ {
+ Task CopyFileAsync(string sourceFilePath, string destinationFolderPath);
+ Task GetFileStreamAsync(string folderPath, string fileName);
+ Task GetFileContentByApplicationUriAsync(string resourcePath);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IFolderMenuItem.cs b/Wino.Core.Domain/Interfaces/IFolderMenuItem.cs
new file mode 100644
index 00000000..a361144a
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IFolderMenuItem.cs
@@ -0,0 +1,30 @@
+using System.Collections.Generic;
+using Wino.Core.Domain.Entities;
+using Wino.Core.Domain.Enums;
+using Wino.Core.Domain.Models.Folders;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IFolderMenuItem : IBaseFolderMenuItem
+ {
+ MailAccount ParentAccount { get; }
+ }
+
+ public interface IMergedAccountFolderMenuItem : IBaseFolderMenuItem { }
+
+ public interface IBaseFolderMenuItem : IMenuItem
+ {
+ string FolderName { get; }
+ bool IsSynchronizationEnabled { get; }
+ int UnreadItemCount { get; set; }
+ SpecialFolderType SpecialFolderType { get; }
+ IEnumerable HandlingFolders { get; }
+ bool IsMoveTarget { get; }
+ bool IsSticky { get; }
+ bool IsSystemFolder { get; }
+ bool ShowUnreadCount { get; }
+ string AssignedAccountName { get; }
+
+ void UpdateFolder(IMailItemFolder folder);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IFolderService.cs b/Wino.Core.Domain/Interfaces/IFolderService.cs
new file mode 100644
index 00000000..9b58ce11
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IFolderService.cs
@@ -0,0 +1,92 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Wino.Core.Domain.Entities;
+using Wino.Core.Domain.Enums;
+using Wino.Core.Domain.Models.Folders;
+using Wino.Core.Domain.Models.MailItem;
+using Wino.Core.Domain.Models.Synchronization;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IFolderService
+ {
+ Task GetFolderStructureForAccountAsync(Guid accountId, bool includeHiddenFolders);
+ Task GetFolderAsync(Guid folderId);
+ Task GetFolderAsync(Guid accountId, string remoteFolderId);
+ Task> GetFoldersAsync(Guid accountId);
+ Task> GetUnreadUpdateFoldersAsync(Guid accountId);
+ Task SetSpecialFolderAsync(Guid folderId, SpecialFolderType type);
+ Task GetSpecialFolderByAccountIdAsync(Guid accountId, SpecialFolderType type);
+ Task GetCurrentItemCountForFolder(Guid folderId);
+ Task GetFolderNotificationBadgeAsync(Guid folderId);
+ Task ChangeStickyStatusAsync(Guid folderId, bool isSticky);
+ Task UpdateCustomServerMailListAsync(Guid accountId, List folders);
+
+ Task UpdateSystemFolderConfigurationAsync(Guid accountId, SystemFolderConfiguration configuration);
+ Task ChangeFolderSynchronizationStateAsync(Guid folderId, bool isSynchronizationEnabled);
+ Task ChangeFolderShowUnreadCountStateAsync(Guid folderId, bool showUnreadCount);
+
+ Task> GetSynchronizationFoldersAsync(SynchronizationOptions options);
+
+ ///
+ /// Returns the folder - mail mapping for the given mail copy ids.
+ ///
+ Task> GetMailFolderPairMetadatasAsync(IEnumerable mailCopyIds);
+
+ ///
+ /// Returns the folder - mail mapping for the given mail copy id.
+ ///
+ Task> GetMailFolderPairMetadatasAsync(string mailCopyId);
+
+ // v2
+
+ ///
+ /// Performs bulk update for the given folders.
+ /// Used in Gmail.
+ ///
+ /// Account that folders belong to.
+ /// Folders to update.
+ Task BulkUpdateFolderStructureAsync(Guid accountId, List allFolders);
+
+ ///
+ /// Updates Folder's delta synchronization identifier.
+ /// Only used in Outlook since it does per-folder sync.
+ ///
+ /// Folder id
+ /// New synchronization identifier.
+ /// New identifier if success.
+ Task UpdateFolderDeltaSynchronizationIdentifierAsync(Guid folderId, string synchronizationIdentifier);
+
+ ///
+ /// Deletes the folder for the given account by remote folder id.
+ ///
+ /// Account to remove from.
+ /// Remote folder id.
+ ///
+ Task DeleteFolderAsync(Guid accountId, string remoteFolderId);
+
+ ///
+ /// Adds a new folder.
+ ///
+ /// Folder to add.
+ Task InsertFolderAsync(MailItemFolder folder);
+
+
+ ///
+ /// Returns the known uids for the given folder.
+ /// Only used for IMAP
+ ///
+ /// Folder to get uIds for
+ Task> GetKnownUidsForFolderAsync(Guid folderId);
+
+ ///
+ /// Checks if Inbox special folder exists for an account.
+ ///
+ /// Account id to check for.
+ /// True if Inbox exists, False if not.
+ Task IsInboxAvailableForAccountAsync(Guid accountId);
+
+ Task TestAsync();
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IFontService.cs b/Wino.Core.Domain/Interfaces/IFontService.cs
new file mode 100644
index 00000000..ff00cdab
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IFontService.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+using Wino.Core.Domain.Enums;
+using Wino.Core.Domain.Models.Reader;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IFontService
+ {
+ List GetReaderFonts();
+ ReaderFontModel GetCurrentReaderFont();
+ int GetCurrentReaderFontSize();
+
+ void ChangeReaderFont(ReaderFont font);
+ void ChangeReaderFontSize(int size);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IImapTestService.cs b/Wino.Core.Domain/Interfaces/IImapTestService.cs
new file mode 100644
index 00000000..1288bc39
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IImapTestService.cs
@@ -0,0 +1,10 @@
+using System.Threading.Tasks;
+using Wino.Core.Domain.Entities;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IImapTestService
+ {
+ Task TestImapConnectionAsync(CustomServerInformation serverInformation);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IInitializeAsync.cs b/Wino.Core.Domain/Interfaces/IInitializeAsync.cs
new file mode 100644
index 00000000..1850a7c0
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IInitializeAsync.cs
@@ -0,0 +1,12 @@
+using System.Threading.Tasks;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ ///
+ /// An interface that all startup services must implement.
+ ///
+ public interface IInitializeAsync
+ {
+ Task InitializeAsync();
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IKeyPressService.cs b/Wino.Core.Domain/Interfaces/IKeyPressService.cs
new file mode 100644
index 00000000..724ad0c4
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IKeyPressService.cs
@@ -0,0 +1,8 @@
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IKeyPressService
+ {
+ bool IsCtrlKeyPressed();
+ bool IsShiftKeyPressed();
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/ILaunchProtocolService.cs b/Wino.Core.Domain/Interfaces/ILaunchProtocolService.cs
new file mode 100644
index 00000000..5c141d4b
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/ILaunchProtocolService.cs
@@ -0,0 +1,10 @@
+using System.Collections.Specialized;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface ILaunchProtocolService
+ {
+ object LaunchParameter { get; set; }
+ NameValueCollection MailtoParameters { get; set; }
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/ILogInitializer.cs b/Wino.Core.Domain/Interfaces/ILogInitializer.cs
new file mode 100644
index 00000000..f5f7e97d
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/ILogInitializer.cs
@@ -0,0 +1,9 @@
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface ILogInitializer
+ {
+ void SetupLogger(string logFolderPath);
+
+ void RefreshLoggingLevel();
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IMailService.cs b/Wino.Core.Domain/Interfaces/IMailService.cs
new file mode 100644
index 00000000..7b09dc51
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IMailService.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using MimeKit;
+using Wino.Core.Domain.Entities;
+using Wino.Core.Domain.Models.MailItem;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IMailService
+ {
+ Task GetSingleMailItemAsync(string mailCopyId, string remoteFolderId);
+ Task GetSingleMailItemAsync(Guid uniqueMailId);
+ Task CreateDraftAsync(MailAccount composerAccount, MimeMessage generatedReplyMime, MimeMessage replyingMimeMessage = null, IMailItem replyingMailItem = null);
+ Task> FetchMailsAsync(MailListInitializationOptions options);
+
+ Task> GetMailIdsByFolderIdAsync(Guid folderId);
+
+ // v2
+
+ ///
+ /// Deletes all mail copies for all folders.
+ ///
+ /// Account to remove from
+ /// Mail copy id to remove.
+ Task DeleteMailAsync(Guid accountId, string mailCopyId);
+
+ Task ChangeReadStatusAsync(string mailCopyId, bool isRead);
+ Task ChangeFlagStatusAsync(string mailCopyId, bool isFlagged);
+
+ Task CreateAssignmentAsync(Guid accountId, string mailCopyId, string remoteFolderId);
+ Task DeleteAssignmentAsync(Guid accountId, string mailCopyId, string remoteFolderId);
+
+ Task CreateMailAsync(Guid accountId, NewMailItemPackage package);
+
+ ///
+ /// Maps new mail item with the existing local draft copy.
+ /// In case of failure, it returns false.
+ /// Then synchronizers must insert a new mail item.
+ ///
+ /// Id of the account. It's important to map to the account since if the user use the same account with different providers, this call must map the correct one.
+ /// UniqueId of the local draft copy.
+ /// New assigned remote mail item id.
+ /// New assigned draft id if exists.
+ /// New message's thread/conversation id.
+ /// True if mapping is done. False if local copy doesn't exists.
+ Task MapLocalDraftAsync(Guid accountId, Guid localDraftCopyUniqueId, string newMailCopyId, string newDraftId, string newThreadId);
+
+ ///
+ /// Maps new mail item with the existing local draft copy.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task MapLocalDraftAsync(string newMailCopyId, string newDraftId, string newThreadId);
+
+ Task CreateDraftMimeMessageAsync(Guid accountId, DraftCreationOptions options);
+ Task UpdateMailAsync(MailCopy mailCopy);
+
+ ///
+ /// Gets the new inserted unread mails after the synchronization.
+ ///
+ /// Account id.
+ ///
+ /// Mail ids that synchronizer tried to download. If there was an issue with the
+ /// Items that tried and actually downloaded may differ. This function will return only new inserted ones.
+ ///
+ /// Newly inserted unread mails inside the Inbox folder.
+ Task> GetDownloadedUnreadMailsAsync(Guid accountId, IEnumerable downloadedMailCopyIds);
+
+ ///
+ /// Returns the account that this mail copy unique id is assigned.
+ /// Used in toast notification handler.
+ ///
+ /// Unique id of the mail item.
+ /// Account that mail belongs to.
+ Task GetMailAccountByUniqueIdAsync(Guid uniqueMailId);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IMenuItem.cs b/Wino.Core.Domain/Interfaces/IMenuItem.cs
new file mode 100644
index 00000000..68997e3f
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IMenuItem.cs
@@ -0,0 +1,41 @@
+using System;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IMenuItem
+ {
+ ///
+ /// An id that this menu item holds.
+ /// For an account, it's AccountId.
+ /// For folder, it's FolderId.
+ /// For merged account, it's MergedAccountId.
+ /// Null if it's a menu item that doesn't hold any valuable entity.
+ ///
+ Guid? EntityId { get; }
+
+ ///
+ /// Is any of the sub items that this menu item contains selected.
+ ///
+ // bool IsChildSelected { get; }
+
+ ///
+ /// Whether the menu item is expanded or not.
+ ///
+ bool IsExpanded { get; set; }
+
+ ///
+ /// Whether the menu item is selected or not.
+ ///
+ bool IsSelected { get; set; }
+
+ ///
+ /// Parent menu item that contains this menu item.
+ ///
+ IMenuItem ParentMenuItem { get; }
+
+ ///
+ /// Recursively expand all parent menu items if parent exists, starting from parent.
+ ///
+ void Expand();
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IMenuOperation.cs b/Wino.Core.Domain/Interfaces/IMenuOperation.cs
new file mode 100644
index 00000000..48279547
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IMenuOperation.cs
@@ -0,0 +1,8 @@
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IMenuOperation
+ {
+ bool IsEnabled { get; }
+ string Identifier { get; }
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/INativeAppService.cs b/Wino.Core.Domain/Interfaces/INativeAppService.cs
new file mode 100644
index 00000000..4abd1dc6
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/INativeAppService.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Threading.Tasks;
+using Wino.Core.Domain.Models.Authorization;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface INativeAppService
+ {
+ string GetWebAuthenticationBrokerUri();
+ Task GetMimeMessageStoragePath();
+ Task GetQuillEditorBundlePathAsync();
+ Task LaunchFileAsync(string filePath);
+ Task LaunchUriAsync(Uri uri);
+ bool IsAppRunning();
+
+ string GetFullAppVersion();
+
+ Task PinAppToTaskbarAsync();
+
+ ///
+ /// Some cryptographic shit is needed for requesting Google authentication in UWP.
+ ///
+ GoogleAuthorizationRequest GetGoogleAuthorizationRequest();
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/INavigationAware.cs b/Wino.Core.Domain/Interfaces/INavigationAware.cs
new file mode 100644
index 00000000..222d7c31
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/INavigationAware.cs
@@ -0,0 +1,10 @@
+using Wino.Core.Domain.Models.Navigation;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface INavigationAware
+ {
+ void OnNavigatedTo(NavigationMode mode, object parameters);
+ void OnNavigatedFrom(NavigationMode mode, object parameters);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/INotificationBuilder.cs b/Wino.Core.Domain/Interfaces/INotificationBuilder.cs
new file mode 100644
index 00000000..683bff44
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/INotificationBuilder.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Wino.Core.Domain.Models.MailItem;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface INotificationBuilder
+ {
+ ///
+ /// Creates toast notifications for new mails.
+ ///
+ Task CreateNotificationsAsync(Guid inboxFolderId, IEnumerable newMailItems);
+
+ ///
+ /// Gets the unread Inbox messages for each account and updates the taskbar icon.
+ ///
+ ///
+ Task UpdateTaskbarIconBadgeAsync();
+
+ ///
+ /// Creates test notification for test purposes.
+ ///
+ Task CreateTestNotificationAsync(string title, string message);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IPreferencesService.cs b/Wino.Core.Domain/Interfaces/IPreferencesService.cs
new file mode 100644
index 00000000..38474cdb
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IPreferencesService.cs
@@ -0,0 +1,144 @@
+using System;
+using Wino.Core.Domain.Enums;
+using Wino.Core.Domain.Models.Reader;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IPreferencesService
+ {
+ ///
+ /// When any of the preferences are changed.
+ ///
+ event EventHandler PreferenceChanged;
+
+ ///
+ /// Setting: For changing the mail display container mode.
+ ///
+ MailListDisplayMode MailItemDisplayMode { get; set; }
+
+ ///
+ /// Setting: Marking the item as read preference mode.
+ ///
+ MailMarkAsOption MarkAsPreference { get; set; }
+
+ ///
+ /// Setting: Preferred time format for mail display.
+ ///
+ bool Prefer24HourTimeFormat { get; set; }
+
+ ///
+ /// Setting: How many seconds should be waited on rendering page to mark item as read.
+ ///
+ int MarkAsDelay { get; set; }
+
+ ///
+ /// Setting: Ask comfirmation from the user during permanent delete.
+ ///
+ bool IsHardDeleteProtectionEnabled { get; set; }
+
+ ///
+ /// Setting: Thread mails into conversations.
+ ///
+ bool IsThreadingEnabled { get; set; }
+
+ ///
+ /// Setting: Show sender pictures in mail list.
+ ///
+ bool IsShowSenderPicturesEnabled { get; set; }
+
+ ///
+ /// Setting: Show preview text in mail list.
+ ///
+ bool IsShowPreviewEnabled { get; set; }
+
+ ///
+ /// Setting: Enable/disable semantic zoom on clicking date headers.
+ ///
+ bool IsSemanticZoomEnabled { get; set; }
+
+ ///
+ /// Setting: Set whether 'img' tags in rendered HTMLs should be removed.
+ ///
+ bool RenderImages { get; set; }
+
+ ///
+ /// Setting: Set whether 'style' tags in rendered HTMls should be removed.
+ ///
+ bool RenderStyles { get; set; }
+
+ ///
+ /// Gets the preferred rendering options for HTML rendering.
+ ///
+ MailRenderingOptions GetRenderingOptions();
+
+ ///
+ /// Setting: Swipe mail operation when mails are swiped to right.
+ ///
+ MailOperation RightSwipeOperation { get; set; }
+
+ ///
+ /// Setting: Swipe mail operation when mails are swiped to left.
+ ///
+ MailOperation LeftSwipeOperation { get; set; }
+
+ ///
+ /// Setting: Whether hover actions on mail pointer hover is enabled or not.
+ ///
+ bool IsHoverActionsEnabled { get; set; }
+
+ ///
+ /// Setting: Hover action on the left when the mail is hovered over.
+ ///
+ MailOperation LeftHoverAction { get; set; }
+
+ ///
+ /// Setting: Hover action on the center when the mail is hovered over.
+ ///
+ MailOperation CenterHoverAction { get; set; }
+
+ ///
+ /// Setting: Hover action on the right when the mail is hovered over.
+ ///
+ MailOperation RightHoverAction { get; set; }
+
+ ///
+ /// Setting: Whether logs are enabled or not.
+ ///
+ bool IsLoggingEnabled { get; set; }
+
+ ///
+ /// Setting: Whether Mailkit Protocol Logger is enabled for ImapTestService or not.
+ ///
+ bool IsMailkitProtocolLoggerEnabled { get; set; }
+
+ ///
+ /// Setting: Which entity id (merged account or folder) should be expanded automatically on startup.
+ ///
+ Guid? StartupEntityId { get; set; }
+
+ ///
+ /// Setting: Display language for the application.
+ ///
+ AppLanguage CurrentLanguage { get; set; }
+
+ ///
+ /// Setting: Display font for the mail reader. Not composer.
+ ///
+ ReaderFont ReaderFont { get; set; }
+
+ ///
+ /// Setting: Font size for the mail reader. Not composer.
+ ///
+ int ReaderFontSize { get; set; }
+
+ ///
+ /// Setting: Whether the navigation pane is opened on the last session or not.
+ ///
+ bool IsNavigationPaneOpened { get; set; }
+
+ ///
+ /// Setting: Whether the next item should be automatically selected once the current item is moved or removed.
+ ///
+ bool AutoSelectNextItem { get; set; }
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IProviderDetail.cs b/Wino.Core.Domain/Interfaces/IProviderDetail.cs
new file mode 100644
index 00000000..e43c6044
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IProviderDetail.cs
@@ -0,0 +1,13 @@
+using Wino.Core.Domain.Enums;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IProviderDetail
+ {
+ MailProviderType Type { get; }
+ string Name { get; }
+ string Description { get; }
+ string ProviderImage { get; }
+ bool IsSupported { get; }
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IProviderService.cs b/Wino.Core.Domain/Interfaces/IProviderService.cs
new file mode 100644
index 00000000..f961b0ea
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IProviderService.cs
@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+using Wino.Core.Domain.Enums;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IProviderService
+ {
+ List GetProviderDetails();
+ IProviderDetail GetProviderDetail(MailProviderType type);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IRequestBundle.cs b/Wino.Core.Domain/Interfaces/IRequestBundle.cs
new file mode 100644
index 00000000..dca28129
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IRequestBundle.cs
@@ -0,0 +1,60 @@
+using System.Collections.Generic;
+using Wino.Core.Domain.Entities;
+using Wino.Core.Domain.Enums;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ ///
+ /// Represents a group of requests.
+ ///
+ public interface IRequestBundle
+ {
+ string BundleId { get; set; }
+ IRequestBase Request { get; }
+ }
+
+ ///
+ /// Represents a group of requests with their native response types.
+ ///
+ /// Native request type from each synchronizer to store.
+ public interface IRequestBundle : IRequestBundle
+ {
+ TRequest NativeRequest { get; }
+ }
+
+ public interface IRequestBase
+ {
+ ///
+ /// Synchronizer option to perform.
+ ///
+ MailSynchronizerOperation Operation { get; }
+
+ ///
+ /// UI changes to apply to the item before sending the request to the server.
+ /// Changes here only affect the UI, not the item itself.
+ /// Changes here are reverted if the request fails by calling .
+ ///
+ void ApplyUIChanges();
+
+ ///
+ /// Reverts the UI changes applied by if the request fails.
+ ///
+ void RevertUIChanges();
+ }
+
+ public interface IRequest : IRequestBase
+ {
+ MailCopy Item { get; }
+ IBatchChangeRequest CreateBatch(IEnumerable requests);
+ }
+
+ public interface IFolderRequest : IRequestBase
+ {
+ MailItemFolder Folder { get; }
+ }
+
+ public interface IBatchChangeRequest : IRequestBase
+ {
+ IEnumerable Items { get; }
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/ISignatureService.cs b/Wino.Core.Domain/Interfaces/ISignatureService.cs
new file mode 100644
index 00000000..14f7f75c
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/ISignatureService.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Threading.Tasks;
+using Wino.Core.Domain.Entities;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface ISignatureService
+ {
+ ///
+ /// Returns the assigned account signature for the account.
+ ///
+ ///
+ ///
+ Task GetAccountSignatureAsync(Guid accountId);
+
+ ///
+ /// Creates the initial signature for new created accounts.
+ ///
+ ///
+ ///
+ Task CreateDefaultSignatureAsync(Guid accountId);
+
+ ///
+ /// Updates account's existing signature with the given HTML signature.
+ ///
+ Task UpdateAccountSignatureAsync(Guid accountId, string htmlBody);
+
+ ///
+ /// Disabled signature for the account and deletes existing signature.
+ ///
+ Task DeleteAccountSignatureAssignment(Guid accountId);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IStatePersistenceService.cs b/Wino.Core.Domain/Interfaces/IStatePersistenceService.cs
new file mode 100644
index 00000000..f6a8cf73
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IStatePersistenceService.cs
@@ -0,0 +1,47 @@
+using System;
+using System.ComponentModel;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IStatePersistanceService : INotifyPropertyChanged
+ {
+ event EventHandler StatePropertyChanged;
+
+ ///
+ /// True when there is an active renderer for selected mail.
+ ///
+ bool IsReadingMail { get; set; }
+
+ ///
+ /// Shell's app bar title string.
+ ///
+ string CoreWindowTitle { get; set; }
+
+ ///
+ /// When only reader page is visible in small sized window.
+ ///
+ bool IsReaderNarrowed { get; set; }
+
+ ///
+ /// Should display back button on the shell title bar.
+ ///
+ bool IsBackButtonVisible { get; }
+
+
+ ///
+ /// Setting: Opened pane length for the navigation view.
+ ///
+ double OpenPaneLength { get; set; }
+
+ ///
+ /// Whether the mail rendering page should be shifted from top to adjust the design
+ /// for standalone EML viewer or not.
+ ///
+ bool ShouldShiftMailRenderingDesign { get; set; }
+
+ ///
+ /// Setting: Mail list pane length for listing mails.
+ ///
+ double MailListPaneLength { get; set; }
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IStoreManagementService.cs b/Wino.Core.Domain/Interfaces/IStoreManagementService.cs
new file mode 100644
index 00000000..36e3ebc9
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IStoreManagementService.cs
@@ -0,0 +1,19 @@
+using System.Threading.Tasks;
+using Wino.Core.Domain.Enums;
+using Wino.Core.Domain.Models.Store;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IStoreManagementService
+ {
+ ///
+ /// Checks whether user has the type of an add-on purchased.
+ ///
+ Task HasProductAsync(StoreProductType productType);
+
+ ///
+ /// Attempts to purchase the given add-on.
+ ///
+ Task PurchaseAsync(StoreProductType productType);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IStoreRatingDialog.cs b/Wino.Core.Domain/Interfaces/IStoreRatingDialog.cs
new file mode 100644
index 00000000..c56ef4a4
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IStoreRatingDialog.cs
@@ -0,0 +1,8 @@
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IStoreRatingDialog
+ {
+ bool DontAskAgain { get; }
+ bool RateWinoClicked { get; }
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IStoreRatingService.cs b/Wino.Core.Domain/Interfaces/IStoreRatingService.cs
new file mode 100644
index 00000000..7b1ba764
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IStoreRatingService.cs
@@ -0,0 +1,10 @@
+using System.Threading.Tasks;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IStoreRatingService
+ {
+ Task PromptRatingDialogAsync();
+ Task LaunchStorePageForReviewAsync();
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/ISynchronizationProgress.cs b/Wino.Core.Domain/Interfaces/ISynchronizationProgress.cs
new file mode 100644
index 00000000..eb952cf7
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/ISynchronizationProgress.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ ///
+ /// An interface for reporting progress of the synchronization.
+ /// Gmail does not support reporting folder progress.
+ /// For others, account progress is calculated based on the number of folders.
+ ///
+ public interface ISynchronizationProgress
+ {
+ ///
+ /// Reports account synchronization progress.
+ ///
+ /// Account id for the report.
+ /// Value. This is always between 0 - 100
+ void AccountProgressUpdated(Guid accountId, int progress);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IThemeService.cs b/Wino.Core.Domain/Interfaces/IThemeService.cs
new file mode 100644
index 00000000..57c3f471
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IThemeService.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Wino.Core.Domain.Enums;
+using Wino.Core.Domain.Models.Personalization;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IThemeService : IInitializeAsync
+ {
+ event EventHandler ElementThemeChanged;
+ event EventHandler AccentColorChangedBySystem;
+ event EventHandler AccentColorChanged;
+
+ Task> GetAvailableThemesAsync();
+ Task CreateNewCustomThemeAsync(string themeName, string accentColor, byte[] wallpaperData);
+ Task> GetCurrentCustomThemesAsync();
+
+ Task ApplyCustomThemeAsync(bool isInitializing);
+
+ // Settings
+ ApplicationElementTheme RootTheme { get; set; }
+ Guid CurrentApplicationThemeId { get; set; }
+ string AccentColor { get; set; }
+ string GetSystemAccentColorHex();
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IThreadingStrategy.cs b/Wino.Core.Domain/Interfaces/IThreadingStrategy.cs
new file mode 100644
index 00000000..ed5d57f0
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IThreadingStrategy.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Wino.Core.Domain.Entities;
+using Wino.Core.Domain.Models.MailItem;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IThreadingStrategy
+ {
+ Task> ThreadItemsAsync(List items);
+ bool ShouldThreadWithItem(IMailItem originalItem, IMailItem targetItem);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IThreadingStrategyProvider.cs b/Wino.Core.Domain/Interfaces/IThreadingStrategyProvider.cs
new file mode 100644
index 00000000..9e3fa87b
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IThreadingStrategyProvider.cs
@@ -0,0 +1,13 @@
+using Wino.Core.Domain.Enums;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IThreadingStrategyProvider
+ {
+ ///
+ /// Returns corresponding threading strategy that applies to given provider type.
+ ///
+ /// Provider type.
+ IThreadingStrategy GetStrategy(MailProviderType mailProviderType);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/ITranslationService.cs b/Wino.Core.Domain/Interfaces/ITranslationService.cs
new file mode 100644
index 00000000..e756f3cd
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/ITranslationService.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Wino.Core.Domain.Enums;
+using Wino.Core.Domain.Models.Translations;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface ITranslationService : IInitializeAsync
+ {
+ Task InitializeLanguageAsync(AppLanguage language, bool ignoreCurrentLanguageCheck = false);
+ List GetAvailableLanguages();
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IUnderlyingThemeService.cs b/Wino.Core.Domain/Interfaces/IUnderlyingThemeService.cs
new file mode 100644
index 00000000..5de11c78
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IUnderlyingThemeService.cs
@@ -0,0 +1,7 @@
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IUnderlyingThemeService
+ {
+ bool IsUnderlyingThemeDark();
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IWinoNavigationService.cs b/Wino.Core.Domain/Interfaces/IWinoNavigationService.cs
new file mode 100644
index 00000000..ba5cf026
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IWinoNavigationService.cs
@@ -0,0 +1,18 @@
+using Wino.Core.Domain.Enums;
+using Wino.Core.Domain.Models.MailItem;
+using Wino.Core.Domain.Models.Navigation;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IWinoNavigationService
+ {
+ bool Navigate(WinoPage page,
+ object parameter = null,
+ NavigationReferenceFrame frame = NavigationReferenceFrame.ShellFrame,
+ NavigationTransitionType transition = NavigationTransitionType.None);
+ void NavigateCompose(IMailItem mailItem, NavigationTransitionType transition = NavigationTransitionType.None);
+ void NavigateRendering(IMailItem mailItem, NavigationTransitionType transition = NavigationTransitionType.None);
+ void NavigateRendering(MimeMessageInformation mimeMessageInformation, NavigationTransitionType transition = NavigationTransitionType.None);
+ void NavigateFolder(NavigateMailFolderEventArgs args);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IWinoRequestDelegator.cs b/Wino.Core.Domain/Interfaces/IWinoRequestDelegator.cs
new file mode 100644
index 00000000..9782e4dd
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IWinoRequestDelegator.cs
@@ -0,0 +1,35 @@
+using System.Threading.Tasks;
+using Wino.Core.Domain.Enums;
+using Wino.Core.Domain.Models.Folders;
+using Wino.Core.Domain.Models.MailItem;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IWinoRequestDelegator
+ {
+ ///
+ /// Prepares requires IRequest collection for mail actions and executes them via proper synchronizers.
+ ///
+ /// Preperation model that encapsulates action and mail items.
+ Task ExecuteAsync(MailOperationPreperationRequest prerperationRequest);
+
+ ///
+ /// Queues new draft creation request for synchronizer.
+ ///
+ /// A class that holds the parameters for creating a draft.
+ Task ExecuteAsync(DraftPreperationRequest draftPreperationRequest);
+
+ ///
+ /// Queues a new request for synchronizer to send a draft.
+ ///
+ /// Draft sending request.
+ Task ExecuteAsync(SendDraftPreparationRequest sendDraftPreperationRequest);
+
+ ///
+ /// Prepares requires IRequest collection for folder actions and executes them via proper synchronizers.
+ ///
+ /// Folder operation to execute.
+ /// Target folder
+ Task ExecuteAsync(FolderOperation operation, IMailItemFolder folderStructure);
+ }
+}
diff --git a/Wino.Core.Domain/Interfaces/IWinoRequestProcessor.cs b/Wino.Core.Domain/Interfaces/IWinoRequestProcessor.cs
new file mode 100644
index 00000000..c35b4e9c
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IWinoRequestProcessor.cs
@@ -0,0 +1,22 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Wino.Core.Domain.Enums;
+using Wino.Core.Domain.Models.Folders;
+using Wino.Core.Domain.Models.MailItem;
+using Wino.Core.Domain.Models.Requests;
+
+namespace Wino.Core.Domain.Interfaces
+{
+ public interface IWinoRequestProcessor
+ {
+ Task PrepareFolderRequestAsync(FolderOperation operation, IMailItemFolder mailItemFolder);
+
+ ///
+ /// Prepares proper Wino requests for synchronizers to execute categorized by AccountId and FolderId.
+ ///
+ /// User action
+ /// Selected mails.
+ /// When required folder target is not available for account.
+ Task> PrepareRequestsAsync(MailOperationPreperationRequest request);
+ }
+}
diff --git a/Wino.Core.Domain/Models/Accounts/ImapAuthenticationMethodModel.cs b/Wino.Core.Domain/Models/Accounts/ImapAuthenticationMethodModel.cs
new file mode 100644
index 00000000..f28b9d6e
--- /dev/null
+++ b/Wino.Core.Domain/Models/Accounts/ImapAuthenticationMethodModel.cs
@@ -0,0 +1,10 @@
+using Wino.Core.Domain.Enums;
+
+namespace Wino.Core.Domain.Models.Accounts
+{
+ public class ImapAuthenticationMethodModel(ImapAuthenticationMethod imapAuthenticationMethod, string displayName)
+ {
+ public ImapAuthenticationMethod ImapAuthenticationMethod { get; } = imapAuthenticationMethod;
+ public string DisplayName { get; } = displayName;
+ }
+}
diff --git a/Wino.Core.Domain/Models/Accounts/ImapConnectionSecurityModel.cs b/Wino.Core.Domain/Models/Accounts/ImapConnectionSecurityModel.cs
new file mode 100644
index 00000000..a618a490
--- /dev/null
+++ b/Wino.Core.Domain/Models/Accounts/ImapConnectionSecurityModel.cs
@@ -0,0 +1,10 @@
+using Wino.Core.Domain.Enums;
+
+namespace Wino.Core.Domain.Models.Accounts
+{
+ public class ImapConnectionSecurityModel(ImapConnectionSecurity imapConnectionSecurity, string displayName)
+ {
+ public ImapConnectionSecurity ImapConnectionSecurity { get; } = imapConnectionSecurity;
+ public string DisplayName { get; } = displayName;
+ }
+}
diff --git a/Wino.Core.Domain/Models/Accounts/ProviderDetail.cs b/Wino.Core.Domain/Models/Accounts/ProviderDetail.cs
new file mode 100644
index 00000000..dc9a5824
--- /dev/null
+++ b/Wino.Core.Domain/Models/Accounts/ProviderDetail.cs
@@ -0,0 +1,47 @@
+using Wino.Core.Domain.Enums;
+using Wino.Core.Domain.Interfaces;
+
+namespace Wino.Core.Domain.Models.Accounts
+{
+ public class ProviderDetail : IProviderDetail
+ {
+ public MailProviderType Type { get; }
+
+ public string Name { get; }
+
+ public string Description { get; }
+
+ public string ProviderImage => $"ms-appx:///Assets/Providers/{Type}.png";
+
+ public bool IsSupported => Type == MailProviderType.Outlook || Type == MailProviderType.Gmail || Type == MailProviderType.IMAP4;
+
+ public ProviderDetail(MailProviderType type)
+ {
+ Type = type;
+
+ switch (Type)
+ {
+ case MailProviderType.Outlook:
+ Name = "Outlook";
+ Description = "Outlook.com, Live.com, Hotmail, MSN";
+ break;
+ case MailProviderType.Office365:
+ Name = "Office 365";
+ Description = "Office 365, Exchange";
+ break;
+ case MailProviderType.Gmail:
+ Name = "Gmail";
+ Description = Translator.ProviderDetail_Gmail_Description;
+ break;
+ case MailProviderType.Yahoo:
+ Name = "Yahoo";
+ Description = "Yahoo Mail";
+ break;
+ case MailProviderType.IMAP4:
+ Name = Translator.ProviderDetail_IMAP_Title;
+ Description = Translator.ProviderDetail_IMAP_Description;
+ break;
+ }
+ }
+ }
+}
diff --git a/Wino.Core.Domain/Models/Authentication/TokenInformationBase.cs b/Wino.Core.Domain/Models/Authentication/TokenInformationBase.cs
new file mode 100644
index 00000000..27f69abf
--- /dev/null
+++ b/Wino.Core.Domain/Models/Authentication/TokenInformationBase.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace Wino.Core.Domain.Models.Authentication
+{
+ public class TokenInformationBase
+ {
+ public string AccessToken { get; set; }
+ public string RefreshToken { get; set; }
+
+ ///
+ /// UTC date for token expiration.
+ ///
+ public DateTime ExpiresAt { get; set; }
+
+ ///
+ /// Gets the value indicating whether the token is expired or not.
+ ///
+ public bool IsExpired => DateTime.UtcNow >= ExpiresAt;
+ }
+}
diff --git a/Wino.Core.Domain/Models/Authorization/GoogleAuthorizationRequest.cs b/Wino.Core.Domain/Models/Authorization/GoogleAuthorizationRequest.cs
new file mode 100644
index 00000000..455fff47
--- /dev/null
+++ b/Wino.Core.Domain/Models/Authorization/GoogleAuthorizationRequest.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Wino.Core.Domain.Exceptions;
+
+namespace Wino.Core.Domain.Models.Authorization
+{
+ public class GoogleAuthorizationRequest
+ {
+ public const string RedirectUri = "google.pw.oauth2:/oauth2redirect";
+
+ const string authorizationEndpoint = "https://accounts.google.com/o/oauth2/v2/auth";
+ const string CodeChallangeMethod = "S256";
+
+ public GoogleAuthorizationRequest(string state, string codeVerifier, string codeChallange)
+ {
+ State = state;
+ CodeVerifier = codeVerifier;
+ CodeChallange = codeChallange;
+ }
+
+ // Pre
+ public string State { get; set; }
+ public string CodeVerifier { get; set; }
+ public string CodeChallange { get; set; }
+ public string ClientId { get; set; }
+
+ // Post
+ public string AuthorizationCode { get; set; }
+
+ public string BuildRequest(string clientId)
+ {
+ ClientId = clientId;
+
+ // Creates the OAuth 2.0 authorization request.
+ return string.Format("{0}?response_type=code&scope=https://mail.google.com/ https://www.googleapis.com/auth/gmail.labels&redirect_uri={1}&client_id={2}&state={3}&code_challenge={4}&code_challenge_method={5}",
+ authorizationEndpoint,
+ Uri.EscapeDataString(RedirectUri),
+ ClientId,
+ State,
+ CodeChallange,
+ CodeChallangeMethod);
+ }
+
+ public void ValidateAuthorizationCode(Uri callbackUri)
+ {
+ if (callbackUri == null)
+ throw new GoogleAuthenticationException(Translator.Exception_GoogleAuthCallbackNull);
+
+ string queryString = callbackUri.Query;
+
+ Dictionary queryStringParams = queryString.Substring(1).Split('&').ToDictionary(c => c.Split('=')[0], c => Uri.UnescapeDataString(c.Split('=')[1]));
+
+ if (queryStringParams.ContainsKey("error"))
+ throw new GoogleAuthenticationException(string.Format(Translator.Exception_GoogleAuthError, queryStringParams["error"]));
+
+ if (!queryStringParams.ContainsKey("code") || !queryStringParams.ContainsKey("state"))
+ throw new GoogleAuthenticationException(Translator.Exception_GoogleAuthCorruptedCode + queryString);
+
+ // Gets the Authorization code & state
+ string code = queryStringParams["code"];
+ string incomingState = queryStringParams["state"];
+
+ // Compares the receieved state to the expected value, to ensure that
+ // this app made the request which resulted in authorization
+ if (incomingState != State)
+ throw new GoogleAuthenticationException(string.Format(Translator.Exception_GoogleAuthInvalidResponse, incomingState));
+
+ AuthorizationCode = code;
+ }
+ }
+}
diff --git a/Wino.Core.Domain/Models/Authorization/GoogleTokenizationRequest.cs b/Wino.Core.Domain/Models/Authorization/GoogleTokenizationRequest.cs
new file mode 100644
index 00000000..0590df09
--- /dev/null
+++ b/Wino.Core.Domain/Models/Authorization/GoogleTokenizationRequest.cs
@@ -0,0 +1,27 @@
+using System;
+using Wino.Core.Domain.Exceptions;
+
+namespace Wino.Core.Domain.Models.Authorization
+{
+ public class GoogleTokenizationRequest
+ {
+ public GoogleTokenizationRequest(GoogleAuthorizationRequest authorizationRequest)
+ {
+ if (authorizationRequest == null)
+ throw new GoogleAuthenticationException("Authorization request is empty.");
+
+ AuthorizationRequest = authorizationRequest;
+
+ if (string.IsNullOrEmpty(AuthorizationRequest.AuthorizationCode))
+ throw new GoogleAuthenticationException("Authorization request has empty code.");
+ }
+
+ public GoogleAuthorizationRequest AuthorizationRequest { get; set; }
+
+ public string BuildRequest()
+ {
+ return string.Format("code={0}&redirect_uri={1}&client_id={2}&code_verifier={3}&scope=&grant_type=authorization_code",
+ AuthorizationRequest.AuthorizationCode, Uri.EscapeDataString(GoogleAuthorizationRequest.RedirectUri), AuthorizationRequest.ClientId, AuthorizationRequest.CodeVerifier);
+ }
+ }
+}
diff --git a/Wino.Core.Domain/Models/AutoDiscovery/AutoDiscoveryConnectionTestFailedPackage.cs b/Wino.Core.Domain/Models/AutoDiscovery/AutoDiscoveryConnectionTestFailedPackage.cs
new file mode 100644
index 00000000..b4668aac
--- /dev/null
+++ b/Wino.Core.Domain/Models/AutoDiscovery/AutoDiscoveryConnectionTestFailedPackage.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace Wino.Core.Domain.Models.AutoDiscovery
+{
+ public class AutoDiscoveryConnectionTestFailedPackage
+ {
+ public AutoDiscoveryConnectionTestFailedPackage(AutoDiscoverySettings settings, Exception error)
+ {
+ Settings = settings ?? throw new ArgumentNullException(nameof(settings));
+ Error = error ?? throw new ArgumentNullException(nameof(error));
+ }
+
+ public AutoDiscoveryConnectionTestFailedPackage(Exception error)
+ {
+ Error = error ?? throw new ArgumentNullException(nameof(error));
+ }
+
+ public AutoDiscoverySettings Settings { get; set; }
+ public Exception Error { get; set; }
+ }
+}
diff --git a/Wino.Core.Domain/Models/AutoDiscovery/AutoDiscoveryMinimalSettings.cs b/Wino.Core.Domain/Models/AutoDiscovery/AutoDiscoveryMinimalSettings.cs
new file mode 100644
index 00000000..b1135a5b
--- /dev/null
+++ b/Wino.Core.Domain/Models/AutoDiscovery/AutoDiscoveryMinimalSettings.cs
@@ -0,0 +1,9 @@
+namespace Wino.Core.Domain.Models.AutoDiscovery
+{
+ public class AutoDiscoveryMinimalSettings
+ {
+ public string DisplayName { get; set; }
+ public string Email { get; set; }
+ public string Password { get; set; }
+ }
+}
diff --git a/Wino.Core.Domain/Models/AutoDiscovery/AutoDiscoveryProviderSetting.cs b/Wino.Core.Domain/Models/AutoDiscovery/AutoDiscoveryProviderSetting.cs
new file mode 100644
index 00000000..dca80eb0
--- /dev/null
+++ b/Wino.Core.Domain/Models/AutoDiscovery/AutoDiscoveryProviderSetting.cs
@@ -0,0 +1,22 @@
+using Newtonsoft.Json;
+
+namespace Wino.Core.Domain.Models.AutoDiscovery
+{
+ public class AutoDiscoveryProviderSetting
+ {
+ [JsonProperty("protocol")]
+ public string Protocol { get; set; }
+
+ [JsonProperty("address")]
+ public string Address { get; set; }
+
+ [JsonProperty("port")]
+ public int Port { get; set; }
+
+ [JsonProperty("secure")]
+ public string Secure { get; set; }
+
+ [JsonProperty("username")]
+ public string Username { get; set; }
+ }
+}
diff --git a/Wino.Core.Domain/Models/AutoDiscovery/AutoDiscoverySettings.cs b/Wino.Core.Domain/Models/AutoDiscovery/AutoDiscoverySettings.cs
new file mode 100644
index 00000000..74f4ae2e
--- /dev/null
+++ b/Wino.Core.Domain/Models/AutoDiscovery/AutoDiscoverySettings.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+using Newtonsoft.Json;
+using Wino.Core.Domain.Entities;
+
+namespace Wino.Core.Domain.Models.AutoDiscovery
+{
+ public class AutoDiscoverySettings
+ {
+ [JsonProperty("domain")]
+ public string Domain { get; set; }
+
+ [JsonProperty("password")]
+ public string Password { get; set; }
+
+ [JsonProperty("settings")]
+ public List Settings { get; set; }
+
+ ///
+ /// Gets whether this domain requires additional steps for password like app-specific password or sth.
+ ///
+ public bool IsPasswordSupportLinkAvailable => !string.IsNullOrEmpty(Password) && Uri.TryCreate(Password, UriKind.Absolute, out _);
+
+ public AutoDiscoveryMinimalSettings UserMinimalSettings { get; set; }
+
+ public CustomServerInformation ToServerInformation()
+ {
+ var imapSettings = GetImapSettings();
+ var smtpSettings = GetSmptpSettings();
+
+ if (imapSettings == null || smtpSettings == null) return null;
+
+ bool imapRequiresSSL = imapSettings.Secure == "SSL";
+ bool smtpRequiresSSL = smtpSettings.Secure == "SSL";
+
+ string imapUrl = imapSettings.Address;
+ string smtpUrl = smtpSettings.Address;
+
+ string imapUsername = imapSettings.Username;
+ string smtpUsername = smtpSettings.Username;
+
+ int imapPort = imapSettings.Port;
+ int smtpPort = smtpSettings.Port;
+
+ var serverInfo = new CustomServerInformation
+ {
+ Id = Guid.NewGuid(),
+ DisplayName = UserMinimalSettings.DisplayName,
+ Address = UserMinimalSettings.Email,
+ IncomingServerPassword = UserMinimalSettings.Password,
+ OutgoingServerPassword = UserMinimalSettings.Password,
+ IncomingRequiresSSL = imapRequiresSSL,
+ OutgoingRequresSSL = smtpRequiresSSL,
+ IncomingServer = imapUrl,
+ OutgoingServer = smtpUrl,
+ IncomingServerPort = imapPort.ToString(),
+ OutgoingServerPort = smtpPort.ToString(),
+ IncomingServerType = Enums.CustomIncomingServerType.IMAP4,
+ IncomingServerUsername = imapUsername,
+ OutgoingServerUsername = smtpUsername
+ };
+
+ return serverInfo;
+ }
+
+ public AutoDiscoveryProviderSetting GetImapSettings()
+ => Settings?.Find(a => a.Protocol == "IMAP");
+
+ public AutoDiscoveryProviderSetting GetSmptpSettings()
+ => Settings?.Find(a => a.Protocol == "SMTP");
+ }
+}
diff --git a/Wino.Core.Domain/Models/Comparers/DateComparer.cs b/Wino.Core.Domain/Models/Comparers/DateComparer.cs
new file mode 100644
index 00000000..c739ec9e
--- /dev/null
+++ b/Wino.Core.Domain/Models/Comparers/DateComparer.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using Wino.Core.Domain.Models.MailItem;
+
+namespace Wino.Core.Domain.Models.Comparers
+{
+ public class DateComparer : IComparer, IEqualityComparer
+ {
+ public int Compare(IMailItem x, IMailItem y)
+ {
+ return DateTime.Compare(y.CreationDate, x.CreationDate);
+ }
+
+ public new bool Equals(object x, object y)
+ {
+ if (x is IMailItem firstItem && y is IMailItem secondItem)
+ {
+ return firstItem.Equals(secondItem);
+ }
+
+ return false;
+ }
+
+ public int GetHashCode(object obj) => (obj as IMailItem).GetHashCode();
+
+ public DateComparer()
+ {
+
+ }
+ }
+}
diff --git a/Wino.Core.Domain/Models/Comparers/DateTimeComparer.cs b/Wino.Core.Domain/Models/Comparers/DateTimeComparer.cs
new file mode 100644
index 00000000..eab8185e
--- /dev/null
+++ b/Wino.Core.Domain/Models/Comparers/DateTimeComparer.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+
+namespace Wino.Core.Domain.Models.Comparers
+{
+ ///
+ /// Used to insert date grouping into proper place in Reader page.
+ ///
+ public class DateTimeComparer : IComparer
+ {
+ public int Compare(DateTime x, DateTime y)
+ {
+ return DateTime.Compare(y, x);
+ }
+ }
+}
diff --git a/Wino.Core.Domain/Models/Comparers/FolderNameComparer.cs b/Wino.Core.Domain/Models/Comparers/FolderNameComparer.cs
new file mode 100644
index 00000000..8f7e0928
--- /dev/null
+++ b/Wino.Core.Domain/Models/Comparers/FolderNameComparer.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+using Wino.Core.Domain.Entities;
+
+namespace Wino.Core.Domain.Models.Comparers
+{
+ public class FolderNameComparer : IComparer
+ {
+ public int Compare(MailItemFolder x, MailItemFolder y)
+ {
+ return x.FolderName.CompareTo(y.FolderName);
+ }
+ }
+}
diff --git a/Wino.Core.Domain/Models/Comparers/ListItemComparer.cs b/Wino.Core.Domain/Models/Comparers/ListItemComparer.cs
new file mode 100644
index 00000000..d73ca190
--- /dev/null
+++ b/Wino.Core.Domain/Models/Comparers/ListItemComparer.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using Wino.Core.Domain.Models.MailItem;
+
+namespace Wino.Core.Domain.Models.Comparers
+{
+ public class ListItemComparer : IComparer