diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 4902924..0000000 --- a/.editorconfig +++ /dev/null @@ -1,201 +0,0 @@ -# Удалите строку ниже, если вы хотите наследовать параметры .editorconfig из каталогов, расположенных выше в иерархии -root = true - -# Файлы C# -[*.cs] - -#### Основные параметры EditorConfig #### - -# Отступы и интервалы -indent_size = 4 -indent_style = tab -tab_width = 4 - -# Предпочтения для новых строк -end_of_line = crlf -insert_final_newline = false - -#### Рекомендации по написанию кода .NET #### - -# Упорядочение Using -dotnet_separate_import_directive_groups = false -dotnet_sort_system_directives_first = false -file_header_template = unset - -# Предпочтения для this. и Me. -dotnet_style_qualification_for_event = false:silent -dotnet_style_qualification_for_field = false:silent -dotnet_style_qualification_for_method = false:silent -dotnet_style_qualification_for_property = false:silent - -# Параметры использования ключевых слов языка и типов BCL -dotnet_style_predefined_type_for_locals_parameters_members = true:silent -dotnet_style_predefined_type_for_member_access = true:silent - -# Предпочтения для скобок -dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent -dotnet_style_parentheses_in_other_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_require_accessibility_modifiers = for_non_interface_members:silent - -# Выражения уровень предпочтения -dotnet_style_coalesce_expression = true:suggestion -dotnet_style_collection_initializer = true:suggestion -dotnet_style_explicit_tuple_names = true:suggestion -dotnet_style_null_propagation = true:suggestion -dotnet_style_object_initializer = true:suggestion -dotnet_style_operator_placement_when_wrapping = beginning_of_line -dotnet_style_prefer_auto_properties = true:silent -dotnet_style_prefer_compound_assignment = true:suggestion -dotnet_style_prefer_conditional_expression_over_assignment = true:silent -dotnet_style_prefer_conditional_expression_over_return = true:silent -dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion -dotnet_style_prefer_inferred_tuple_names = true:suggestion -dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion -dotnet_style_prefer_simplified_boolean_expressions = true:suggestion -dotnet_style_prefer_simplified_interpolation = true:suggestion - -# Предпочтения для полей -dotnet_style_readonly_field = true:suggestion - -# Настройки параметров -dotnet_code_quality_unused_parameters = all:suggestion - -#### Рекомендации по написанию кода C# #### - -# Предпочтения var -csharp_style_var_elsewhere = false:silent -csharp_style_var_for_built_in_types = false:silent -csharp_style_var_when_type_is_apparent = false:silent - -# Члены, заданные выражениями -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 - -# Настройки соответствия шаблонов -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_switch_expression = true:suggestion - -# Настройки проверки на null -csharp_style_conditional_delegate_call = true:suggestion - -# Предпочтения модификатора -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:silent - -# Предпочтения для блоков кода -csharp_prefer_braces = true:silent -csharp_prefer_simple_using_statement = true:suggestion - -# Выражения уровень предпочтения -csharp_prefer_simple_default_expression = true:suggestion -csharp_style_deconstructed_variable_declaration = true:suggestion -csharp_style_inlined_variable_declaration = true:suggestion -csharp_style_pattern_local_over_anonymous_function = true:suggestion -csharp_style_prefer_index_operator = true:suggestion -csharp_style_prefer_range_operator = 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 -csharp_using_directive_placement = outside_namespace:silent - -#### Правила форматирования C# #### - -# Предпочтения для новых строк -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 - -# Предпочтения для отступов -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 - -# Предпочтения для интервалов -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 - -# Предпочтения переноса -csharp_preserve_single_line_blocks = true -csharp_preserve_single_line_statements = true - -#### Стили именования #### - -# Правила именования - -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_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.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 = - -# Стили именования - -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 diff --git a/.gitignore b/.gitignore index bf86047..4721ffe 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ obj/ # Visual Studio 2015/2017 cache/options directory .vs/ +.idea/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ diff --git a/.vs/OlibKey/DesignTimeBuild/.dtbcache.v2 b/.vs/OlibKey/DesignTimeBuild/.dtbcache.v2 deleted file mode 100644 index 875cc6e..0000000 Binary files a/.vs/OlibKey/DesignTimeBuild/.dtbcache.v2 and /dev/null differ diff --git a/.vs/OlibKey/v16/.suo b/.vs/OlibKey/v16/.suo deleted file mode 100644 index 2bd014d..0000000 Binary files a/.vs/OlibKey/v16/.suo and /dev/null differ diff --git a/App.axaml b/App.axaml index 98915c7..e368cab 100644 --- a/App.axaml +++ b/App.axaml @@ -10,7 +10,7 @@ - + @@ -22,7 +22,6 @@ - - @@ -106,6 +101,9 @@ + - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/App.axaml.cs b/App.axaml.cs index 57f64fe..5973dac 100644 --- a/App.axaml.cs +++ b/App.axaml.cs @@ -3,13 +3,11 @@ using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml.Styling; using Avalonia.Threading; -using OlibKey.Structures; using OlibKey.Views.Controls; using OlibKey.Views.Windows; using System; using System.Diagnostics; using System.Globalization; -using System.IO; using System.Net; using System.Reflection; @@ -17,13 +15,12 @@ namespace OlibKey { public class App : Application { - public static Settings Settings { get; set; } - public static DispatcherTimer Autosave { get; set; } public static DispatcherTimer Autoblock { get; set; } + public static DispatcherTimer ClearingClipboard { get; set; } - private static string ResultCheckUpdate; - private static string ErrorResult; + private static string _resultCheckUpdate; + private static string _errorResult; public static MainWindow MainWindow { get; set; } public static MainWindowViewModel MainWindowViewModel { get; set; } @@ -33,14 +30,10 @@ public override void Initialize() { AvaloniaXamlLoader.Load(this); - Settings = File.Exists(AppDomain.CurrentDomain.BaseDirectory + "settings.xml") - ? Core.SaveAndLoadSettings.LoadSettings() - : new Settings(); - - Current.Styles[2] = !string.IsNullOrEmpty(Settings.Theme) + Current.Styles[2] = !string.IsNullOrEmpty(Program.Settings.Theme) ? new StyleInclude(new Uri("resm:Styles?assembly=OlibKey")) { - Source = new Uri($"avares://OlibKey/Assets/Themes/{Settings.Theme}.axaml") + Source = new Uri($"avares://OlibKey/Assets/Themes/{Program.Settings.Theme}.axaml") } : new StyleInclude(new Uri("resm:Styles?assembly=OlibKey")) { @@ -49,32 +42,39 @@ public override void Initialize() Autosave = new DispatcherTimer(); Autoblock = new DispatcherTimer(); + ClearingClipboard = new DispatcherTimer(); - Autosave.Tick += (s, d) => + Autosave.Tick += (_, __) => { - foreach (TabItem item in MainWindowViewModel.TabItems) MainWindowViewModel.SaveDatabase((DatabaseControl)item.Content); + for (var i = 0; i < MainWindowViewModel.TabItems.Count; i++) + MainWindowViewModel.SaveDatabase((DatabaseControl) MainWindowViewModel.TabItems[i].Content); }; + ClearingClipboard.Tick += (_, __) => + { + ClearingClipboard.Stop(); + Current.Clipboard.ClearAsync(); + MainWindow.MessageStatusBar((string)Current.FindResource("ClipboardIsCleared")); + }; - Autosave.Interval = new TimeSpan(0, Settings.AutosaveDuration, 0); - Autoblock.Interval = new TimeSpan(0, Settings.BlockDuration, 0); - + Autosave.Interval = new TimeSpan(0, Program.Settings.AutosaveDuration, 0); + Autoblock.Interval = new TimeSpan(0, Program.Settings.BlockDuration, 0); - if (Settings.FirstRun) + if (Program.Settings.FirstRun) { - Settings.Language = $"{CultureInfo.CurrentCulture}"; - Settings.FirstRun = false; + Program.Settings.Language = $"{CultureInfo.CurrentCulture}"; + Program.Settings.FirstRun = false; } try { Current.Styles[4] = new StyleInclude(new Uri("resm:Styles?assembly=OlibKey")) { - Source = new Uri($"avares://OlibKey/Assets/Local/lang.{Settings.Language}.axaml") + Source = new Uri($"avares://OlibKey/Assets/Local/lang.{Program.Settings.Language}.axaml") }; } catch { - Settings.Language = null; + Program.Settings.Language = null; Current.Styles[4] = new StyleInclude(new Uri("resm:Styles?assembly=OlibKey")) { Source = new Uri($"avares://OlibKey/Assets/Local/lang.en-US.axaml") @@ -91,53 +91,50 @@ public static async void CheckUpdate(bool b) try { using WebClient wb = new WebClient(); - wb.DownloadStringCompleted += (s, args) => + wb.DownloadStringCompleted += (_, args) => { if (args.Error != null) { - ErrorResult = args.Error.ToString(); + _errorResult = args.Error.ToString(); return; } - ResultCheckUpdate = args.Result; + _resultCheckUpdate = args.Result; }; await wb.DownloadStringTaskAsync(new Uri( "https://raw.githubusercontent.com/MagnificentEagle/OlibKey/master/ForRepository/version.txt")); - float latest = float.Parse(ResultCheckUpdate.Replace(".", "")); + float latest = float.Parse(_resultCheckUpdate.Replace(".", "")); float current = - float.Parse(Assembly.GetExecutingAssembly().GetName().Version.ToString().Replace(".", "")); + float.Parse(Assembly.GetExecutingAssembly().GetName().Version?.ToString().Replace(".", "")!); + if (!(latest > current) && b) { - _ = await MessageBox.Show(MainWindow, + await MessageBox.Show(MainWindow, null, (string)Current.FindResource("MB8"), (string)Current.FindResource("Message"), MessageBox.MessageBoxButtons.Ok, MessageBox.MessageBoxIcon.Information); return; } + if (!(latest > current)) return; if (await MessageBox.Show(MainWindow, null, (string)Current.FindResource("MB4"), (string)Current.FindResource("Message"), MessageBox.MessageBoxButtons.YesNo, MessageBox.MessageBoxIcon.Question) == MessageBox.MessageBoxResult.Yes) { - ProcessStartInfo psi = new ProcessStartInfo + Process.Start(new ProcessStartInfo { FileName = "https://github.com/MagnificentEagle/OlibKey/releases", UseShellExecute = true - }; - Process.Start(psi); + }); } } catch (Exception ex) { if (b) { - if (ErrorResult != null) - _ = await MessageBox.Show(MainWindow, ErrorResult, + await MessageBox.Show(MainWindow, _errorResult ?? ex.ToString(), (string)Current.FindResource("MB5"), (string)Current.FindResource("Error"), MessageBox.MessageBoxButtons.Ok, MessageBox.MessageBoxIcon.Error); - else _ = await MessageBox.Show(MainWindow, ex.ToString(), - (string)Current.FindResource("MB5"), (string)Current.FindResource("Error"), MessageBox.MessageBoxButtons.Ok, - MessageBox.MessageBoxIcon.Error); } } } diff --git a/Assets/Images/Icons.axaml b/Assets/Images/Icons.axaml index 17b8c9c..ae2c7ef 100644 --- a/Assets/Images/Icons.axaml +++ b/Assets/Images/Icons.axaml @@ -107,232 +107,143 @@ - - - + - - - - - - - - + - - - + - - - + - - - + - - - + - - - + - - - - - - - + - - - - - - - - - - - - - - - - - - + - - - - - - + - - - + - - - + - - - - - - - - - - - - - - - - - - - - - - - - + - - - + - - - + - - - + - - - + - - - + - - - + - - - + - - - + - - - - + - - - + - - - + + + + + + + + + + + + + + + + diff --git a/Assets/Local/lang.de-DE.axaml b/Assets/Local/lang.de-DE.axaml index 925a95d..c958550 100644 --- a/Assets/Local/lang.de-DE.axaml +++ b/Assets/Local/lang.de-DE.axaml @@ -11,6 +11,7 @@ Sicher speichern Speichern Sie alle Tresore Login hinzufügen + Korb Einstellungen Melden Sie sich von OlibKey ab Passwortgenerator @@ -19,12 +20,19 @@ Auf Update prüfen OlibKey-Datenbankdatei + Leer + Nicht gefunden + Suche Alle Artikel Ordner Nicht ausgewählt Deaktivieren Sie Artikelname + + Erinnerungen ausführen + Alphabetisch sortieren + Favoriten OlibKey auf GitHub OlibKey auf VK @@ -33,6 +41,9 @@ Bereit Artikel: Geöffnete Basen: + Reinigung erfolgt + Ordner: + Entfernt: Zusammenbruch Erweitern @@ -55,7 +66,10 @@ Verschließen Sie alle Tresore Speicher entsperren Schalte alle Tresore frei - Zeigen OlibKey + + Очистить корзину + Удалить выбранное + Вернуть выбранное Sie müssen zuerst Speicher hochladen oder erstellen! Fehler @@ -67,6 +81,7 @@ Sie können keine Zeichen aus einer leeren Zeichenfolge verlangen! Keine Häkchen ausgewählt oder Passwortlänge angegeben! Derzeit gibt es keine neuen Updates. + Sind Sie sicher, dass Sie Ihren Müll leeren möchten? Erfolgreich! @@ -79,6 +94,9 @@ Alle Tresore wurden erfolgreich gesperrt! Alle Tresore wurden erfolgreich entsperrt! Tresor erfolgreich gesperrt: + In die Zwischenablage kopiert! + Die Zwischenablage wird gelöscht! + Wird geladen... Kleinbuchstaben (abc) Großbuchstaben (ABC) @@ -99,10 +117,18 @@ Auswählen Anzahl der Iterationen: Anzahl der Verschlüsselungsverfahren: + Verwenden Sie die Komprimierung + Verwenden Sie Müll In Feldern mit einem numerischen Eintrag müssen Werte Zahlen enthalten und dürfen nicht Null sein! Sie haben keinen Repository-Pfad ausgewählt oder kein Hauptkennwort angegeben! Sie können keinen Tresor erstellen, wenn dieser Tresor bereits geöffnet ist! + Überprüfen schwacher Passwörter + Gesamtkomplexität: + Fix + Wählen Sie Alle + Hier sind schwache Passwörter, die Sie ersetzen können. Wählen Sie diejenigen aus, die Sie ändern möchten, und klicken Sie auf die Schaltfläche Fix. Der Austausch erfolgt gemäß den Einstellungen des Passwortgenerators. + Öffnen Geben Sie das Master-Passwort ein @@ -116,10 +142,14 @@ Allgemeines Gewölbe Automatisch speichern über: - Blockieren Sie alle Datenbanken (außer mit einer Erinnerung) durch: + Blockieren Sie alle Datenbanken (außer mit einer laufenden Erinnerung) durch: Dauer der Nachrichtenanzeige: Sekunden Protokoll + Tage + Hardwarebeschleunigung (Neustart erforderlich) + Entfernen Sie einen Artikel automatisch aus dem Papierkorb über: + Zwischenablage nach dem Kopieren löschen über: Blendend Düster diff --git a/Assets/Local/lang.en-US.axaml b/Assets/Local/lang.en-US.axaml index 139122c..40914e6 100644 --- a/Assets/Local/lang.en-US.axaml +++ b/Assets/Local/lang.en-US.axaml @@ -11,6 +11,7 @@ Save storage Save all storages Add log in + Trash Settings Exit from OlibKey Password generator @@ -19,12 +20,19 @@ Check for Updates OlibKey Database File + Empty + Not found + Search All items Folder Not chosen Remove selection Item name + + Running reminders + Sort alphabetically + Favorites OlibKey on GitHub OlibKey on VK @@ -33,6 +41,9 @@ Ready Elements: Opened bases: + Cleaning done + Folders: + Removed: Collapse Expand @@ -55,7 +66,10 @@ Lock all storages Unlock storage Unlock all storages - Show OlibKey + + Empty trash + Delete selected + Return selected You must first upload or create storage! Error @@ -67,6 +81,7 @@ You cannot require characters from an empty string! No checkmarks selected or password length specified! There are no new updates at this time. + Are you sure you want to empty your trash? Successfully! @@ -79,6 +94,9 @@ All storages are locked successfully! All storages have been successfully unlocked! Storage locked successfully: + Copied to the clipboard! + Clipboard is cleared! + Loading... Lowercase (abc) Uppercase (ABC) @@ -99,10 +117,18 @@ Select Number of iterations: Number of encryption procedures: + Use compression + Use trash In fields with a numeric entry, values must contain numbers and cannot be zero! You did not select a repository path or did not provide a master password! You cannot create a vault if this vault is already open! + Checking weak passwords + Overall complexity: + Fix + Select all + Here are weak passwords that you can replace. Select the ones you want to change and click on the Fix button. The replacement will take place according to the password generator settings. + Open Enter Master Password @@ -116,10 +142,14 @@ General Storage Autosave via: - Block all databases (except with a reminder) through: + Block all databases (except with a running reminder) through: Message display duration: seconds minutes + days + Hardware acceleration (reboot required) + Automatically remove an item from the trash via: + Clear clipboard after copying via: Dazzling Gloomy diff --git a/Assets/Local/lang.fr-FR.axaml b/Assets/Local/lang.fr-FR.axaml index c512f5b..b2315c3 100644 --- a/Assets/Local/lang.fr-FR.axaml +++ b/Assets/Local/lang.fr-FR.axaml @@ -11,6 +11,7 @@ Enregistrer le stockage Enregistrer tous les coffres Ajouter une connexion + Panier Paramètres Déconnectez-vous d'OlibKey Générateur de mot de passe @@ -19,12 +20,19 @@ Vérifier les mises à jour Fichier de base de données OlibKey + Vide + Pas trouvé + Chercher Tous les articles Dossier Non sélectionné Désélectionner Nom de l'article + + Rappels en cours d'exécution + Trier par ordre alphabétique + Favoris OlibKey sur GitHub OlibKey sur VK @@ -33,6 +41,9 @@ Prêt Articles: Bases ouvertes: + Nettoyage terminé + Dossiers: + Supprimé: Réduire Développer @@ -55,7 +66,10 @@ Verrouiller tous les stockages Déverrouillez le stockage Déverrouiller tous les stockages - Afficher OlibKey + + Poubelle vide + Supprimer sélectionnée + Retour sélectionné Vous devez d'abord télécharger ou créer du stockage! Erreur @@ -67,6 +81,7 @@ Vous ne pouvez pas exiger des caractères d'une chaîne vide! Aucune coche sélectionnée ou longueur de mot de passe spécifiée! Il n'y a aucune nouvelle mise à jour pour le moment. + Voulez-vous vraiment vider votre corbeille? Avec succès! @@ -79,6 +94,9 @@ Tous les stockage ont été verrouillés avec succès! Tous les stockage ont été déverrouillés avec succès! Stockage verrouillé avec succès: + Copié dans le presse-papiers! + Le presse-papiers est effacé! + Chargement... Minuscules (abc) Majuscules (ABC) @@ -99,10 +117,18 @@ Sélectionnez Nombre d'itérations: Nombre de procédures de cryptage: + Utiliser la compression + Utiliser la poubelle Dans les champs avec une entrée numérique, les valeurs doivent contenir des nombres et ne peuvent pas être zéro! Vous n'avez pas sélectionné de chemin de référentiel ou n'avez pas fourni de mot de passe principal! Vous ne pouvez pas créer de coffre-fort si ce coffre-fort est déjà ouvert! + Vérification des mots de passe faibles + Complexité globale: + Réparer + Tout sélectionner + Voici les mots de passe faibles que vous pouvez remplacer. Sélectionnez ceux que vous souhaitez modifier et cliquez sur le bouton Réparer. Le remplacement aura lieu selon les paramètres du générateur de mot de passe. + Ouverte Entrez le mot de passe principal @@ -116,10 +142,14 @@ Général Voûte Sauvegarde automatique via: - Bloquez toutes les bases de données (sauf avec un rappel) via: + Bloquez toutes les bases de données (sauf avec un rappel en cours) via: Durée d'affichage des messages: secondes minutes + journées + Accélération matérielle (redémarrage requis) + Supprimer automatiquement un élément de la corbeille via: + Effacer le presse-papiers après la copie via: Éblouissant Sombre diff --git a/Assets/Local/lang.hy-AM.axaml b/Assets/Local/lang.hy-AM.axaml index ad4d332..a9fc9cd 100644 --- a/Assets/Local/lang.hy-AM.axaml +++ b/Assets/Local/lang.hy-AM.axaml @@ -11,6 +11,7 @@ Պահպանել պահեստ Պահպանեք բոլոր պահոցները Ավելացնել լոգին + Զամբյուղ Կարգավորումներ Դուրս գալ OlibKey-ից Գաղտնաբառի գեներատոր @@ -19,12 +20,19 @@ Ստուգել թարմացումները OlibKey տվյալների շտեմարան + Դատարկ + Չի գտնվել + Որոնել Բոլոր իրերը Թղթապանակ Ընտրված չէ Elնջել Նյութի անվանումը + + Գործարկման հիշեցումներ + Դասավորեք այբբենական կարգով + Ընտրյալներ OlibKey- ը GitHub- ում OlibKey- ը VK- ում @@ -33,6 +41,9 @@ Պատրաստ է Նյութեր: Բացված հիմքերը: + Մաքրումը կատարվում է + Թղթապանակներ: + Հեռացված: Փլուզվել Ընդլայնել @@ -55,7 +66,10 @@ Կողպեք բոլոր պահոցները Բացել պահեստը Բացել բոլոր պահոցները - Ուցադրել OlibKey + + Դատարկ աղբարկղ + Ջնջել ընտրված + Վերադարձնել ընտրված Առաջինը, դուք պետք էք բեռնել կամ ստեղծել պահեստ Սխալ @@ -67,6 +81,7 @@ Դուք չեք կարող պահանջել նիշ դատարկ տողից: Ընտրված չէ նշման նշան կամ գաղտնաբառի երկարություն: Այս պահին նոր թարմացումներ չկան: + Вы дейстивтельно хотите очистить корзину? Հաջող! @@ -79,6 +94,9 @@ Բոլոր պահոցները հաջողությամբ կողպվել են: Բոլոր պահոցները հաջողությամբ բացվել են: Հիմքը հաջողությամբ արգելափակված է. + Պատճենահանվեց clipboard- ին: + Տեսահոլովակը մաքրված է: + Բեռնվում է... Փոքրատառ (abc) Մեծատառ (ABC) @@ -99,9 +117,17 @@ Ընտրել Կրկնությունների քանակը. Գաղտնագրման ընթացակարգերի քանակը. + Օգտագործեք սեղմում + Օգտագործեք զամբյուղը Թվային մուտքագրման դաշտերում արժեքները պետք է պարունակեն թվեր և չեն կարող զրո լինել: Դուք չեք ընտրել պահեստային ուղի կամ չեք տրամադրել վարպետ գաղտնաբառ: Դուք չեք կարող ստեղծել պահոց, եթե այս կամարն արդեն բաց է: + + Ստուգում են թույլ գաղտնաբառերը + Ընդհանուր դժվարություն. + Ուղղել + Ընտրել բոլորը + Ահա թույլ գաղտնաբառերը, որոնք կարող եք փոխարինել: Ընտրեք դրանք, որոնք ցանկանում եք փոխել և կտտացրեք ամրագրման կոճակին: Փոխումը տեղի է ունենալու ըստ գաղտնաբառի գեներատորի պարամետրերի: Բացել Գրեք վարպետության գաղտնաբառը @@ -116,10 +142,14 @@ Գեներալ Պահոց Ավտոմատ խնայողություն միջոցով ՝ - Արգելափակել բոլոր տվյալների բազաները (բացառությամբ հիշեցմամբ) ՝ + Արգելափակել բոլոր տվյալների բազաները (բացառությամբ գործարկման հիշեցման) միջոցով ՝ Հաղորդագրության ցուցադրման տևողությունը. վայրկյան րոպեներ + օրեր + Սարքավորումների արագացում (անհրաժեշտ է վերաբեռնումը) + Ավտոմատ կերպով հանեք իրը ​​զամբյուղից ՝ + Մաքրել clipboard միջոցով պատճենելուց հետո ՝ Զարմանալի Մռայլ diff --git a/Assets/Local/lang.ru-RU.axaml b/Assets/Local/lang.ru-RU.axaml index 57d5b73..4919b19 100644 --- a/Assets/Local/lang.ru-RU.axaml +++ b/Assets/Local/lang.ru-RU.axaml @@ -11,6 +11,7 @@ Сохранить хранилище Сохранить все хранилища Добавить логин + Корзина Настройки Выйти из OlibKey Генератор паролей @@ -19,12 +20,19 @@ Проверить наличие обновлении Файл базы данных OlibKey + Пусто + Не найдено + Поиск Все элементы Папка Не выбрано Снять выделение Название элемента + + Запущенные напоминания + Сортировка по алфавиту + Избранное OlibKey на GitHub OlibKey во ВКонтакте @@ -33,6 +41,9 @@ Готов Элементов: Открыто баз: + Произведена очистка + Папки: + Удалён: Свернуть Развернуть @@ -55,7 +66,10 @@ Заблокировать все хранилища Разблокировать хранилище Разблокировать все хранилища - Показать OlibKey + + Очистить корзину + Удалить выбранное + Вернуть выбранное Сначала вы должны загрузить или создать хранилище! Ошибка @@ -67,6 +81,7 @@ Вы не можете требовать символы из пустой строки! Не выбрано ни одной галочки или не указана длина пароля! На данный момент нет новых обновлений + Вы действительно хотите очистить корзину? Успешно! @@ -79,6 +94,9 @@ Все хранилища успешно заблокированы! Все хранилища успешно разблокированы! Успешно разблокировано хранилище: + Скопировано в буфер обмена! + Буфер обмена очищен! + Идёт загрузка... Строчные (abc) Заглавные (ABC) @@ -99,9 +117,17 @@ Выбрать Количество итерации: Количество процедур шифрования: + Использовать сжатие + Использовать корзину В полях с вводом цифровых значении должны содержать числа и не могут быть равны нулю! Вы не выбрали путь хранилища или не указали мастер-пароль! Вы не сможете создать хранилище, оно уже открыто! + + Проверка слабых паролей + Общая сложность: + Исправить + Выделить все + Здесь представлены слабые пароли, которые можно заменить. Выберите те, которые вы хотите изменить, и нажмите на кнопку Исправить. Замена будет происходить согласно настройкам генератора паролей. Открыть Введите мастер-пароль @@ -116,10 +142,14 @@ Общее Хранилище Автосохранение через: - Заблокировать все базы (кроме с напоминанием) через: + Заблокировать все базы (кроме с запущенным напоминанием) через: Длительность показа сообщения: секунд минут + дней + Аппаратное ускорение (требуется перезагрузка) + Автоматически удалять элемент из корзины через: + Очищать буфер обмена после копирования через: Ослепительная Мрачная diff --git a/Assets/Local/lang.uk-UA.axaml b/Assets/Local/lang.uk-UA.axaml index 12577bb..ea9b055 100644 --- a/Assets/Local/lang.uk-UA.axaml +++ b/Assets/Local/lang.uk-UA.axaml @@ -11,6 +11,7 @@ Зберегти сховище Зберегти всі сховища Додати логін + Кошик Налаштування Вийти з OlibKey Генератор паролей @@ -19,12 +20,19 @@ Перевірити наявність оновленні Файл бази даних OlibKey + Пусто + Не знайдено + Пошук Всі елементи Тека Не вибрано Зняти виділення Назва елемента + + Запущені нагадування + Сортування за алфавітом + Вибране OlibKey на GitHub OlibKey у ВКонтакте @@ -33,6 +41,9 @@ Готовий Елементів: Відкрито баз: + Очищено + Папки: + Вилучений: Згорнути Розгорнути @@ -55,7 +66,10 @@ Заблокувати всі сховища Розблокувати сховище Розблокувати все сховища - Показати OlibKey + + Очистить корзину + Удалить выбранное + Вернуть выбранное Спочатку ви повинні завантажити або створити сховище! Помилка @@ -67,6 +81,7 @@ Ви не можете вимагати символи з порожнього рядка! Не вибрано жодної галочки або не зазначена довжина пароля! На даний момент немає нових оновлень + Ви дійсно хочете очистити кошик? Успішно! @@ -79,6 +94,9 @@ Всі сховища успішно заблоковані! Всі сховища успішно розблоковані! Успішно розблоковано сховище: + Скопійовано в буфер обміну! + Буфер обміну очищений! + Іде завантаження... Рядкові (abc) Заголовні (ABC) @@ -99,9 +117,17 @@ Вибрати Кількість ітерації: Кількість процедур шифрування: + Використовувати стиснення + Використовувати кошик У полях з введенням цифрових значенні повинні містити числа і не можуть бути рівними нулю! Ви не обрали шлях сховища або не вказали майстер-пароль! Ви не зможете створити сховище, якщо це сховище вже відкрито! + + Перевірка слабких паролів + Загальна складність: + Виправити + Виділити все + Тут представлені слабкі паролі, які можна замінити. Виберіть ті, які ви хочете змінити, і натисніть на кнопку Виправити. Заміна відбуватиметься згідно налаштувань генератора паролів. Відкрити Введіть майстер-пароль @@ -116,10 +142,14 @@ Загальна Сховище Автозбереження через: - Заблокувати всі бази (крім з нагадуванням) через: + Заблокувати всі бази (крім з запущеним нагадуванням) через: Тривалість показу повідомлення: секунд хвилин + днів + Апаратне прискорення (потрібне перезавантаження) + Автоматично видаляти елемент з кошика через: + Очищати буфер обміну після копіювання через: Сліпуча Похмура diff --git a/Assets/Themes/Dazzling.axaml b/Assets/Themes/Dazzling.axaml index 517d004..ccd9f31 100644 --- a/Assets/Themes/Dazzling.axaml +++ b/Assets/Themes/Dazzling.axaml @@ -9,7 +9,7 @@ #FFA5A5A5 #FFE3E3E3 #FFFFFFFF - #FFEAEAEA + #FFEDEDED #FF931D60 #FF231E1B #FF333333 diff --git a/Assets/Themes/Gloomy.axaml b/Assets/Themes/Gloomy.axaml index a1f957e..d054e59 100644 --- a/Assets/Themes/Gloomy.axaml +++ b/Assets/Themes/Gloomy.axaml @@ -6,7 +6,7 @@ #FF000000 #FFFFFFFF #FF777777 - #FFA5A5A5 + #FF525252 #FF2B2B2B #FFFFFFFF #FF1C1C1C diff --git a/CHANGELOG.md b/CHANGELOG.md index 42eb056..d208c27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [3.2.0] - 2020-08-26 +### Added +- Added new window "Check for weak passwords" +- You can now mark items as favorites +- Added sorting in search +- Now you can compress the database to save disk space, the option is enabled by default +- Added "Hardware acceleration" option, disabled by default +- Added logging +- Added trash +- Now automatically clears the clipboard after copying + +### Changed +- Moving to .NET 5 Preview 8 +- Migrating to Avalonia 0.10.999-cibuild0010094-beta +- Application icons changed +- Search algorithm rewritten +- ProgressBar changed due to overflow +- In Windows, when Program Files is detected, the program will automatically start with administrator rights +- Context menu buttons for folders in search are now deactivated if a folder is not selected +- Modals run in the middle of the native, not in the middle of the screen +- Improved performance + +### Fixed +- Fixed crash on some OS when opening a database: if there are no selected databases, the program terminates abnormally +- Fixed MessageBox with an exception: it shouldn't stretch to the sides +- Fixed list virtualization for folders + ## [3.1.1] - 2020-08-06 ### Fixed - Fixed crash of the program when loading an icon for login, but there are no network connections diff --git a/Core/Archiving.cs b/Core/Archiving.cs new file mode 100644 index 0000000..9dd552d --- /dev/null +++ b/Core/Archiving.cs @@ -0,0 +1,44 @@ +using System; +using System.IO; +using System.IO.Compression; +using System.Text; + +namespace OlibKey.Core +{ + public static class Compressing + { + public static string Compress(string text) + { + byte[] buffer = Encoding.UTF8.GetBytes(text); + MemoryStream memoryStream = new MemoryStream(); + using (GZipStream gZipStream = new GZipStream(memoryStream, CompressionMode.Compress, true)) + gZipStream.Write(buffer, 0, buffer.Length); + + memoryStream.Position = 0; + + byte[] compressedData = new byte[memoryStream.Length]; + memoryStream.Read(compressedData, 0, compressedData.Length); + + byte[] gZipBuffer = new byte[compressedData.Length + 4]; + Buffer.BlockCopy(compressedData, 0, gZipBuffer, 4, compressedData.Length); + Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gZipBuffer, 0, 4); + + return Convert.ToBase64String(gZipBuffer); + } + public static string Decompress(string text) + { + byte[] gZipBuffer = Convert.FromBase64String(text); + using MemoryStream memoryStream = new MemoryStream(); + int dataLength = BitConverter.ToInt32(gZipBuffer, 0); + memoryStream.Write(gZipBuffer, 4, gZipBuffer.Length - 4); + + byte[] buffer = new byte[dataLength]; + + memoryStream.Position = 0; + using (GZipStream gZipStream = new GZipStream(memoryStream, CompressionMode.Decompress)) + gZipStream.Read(buffer, 0, buffer.Length); + + return Encoding.UTF8.GetString(buffer); + } + } +} diff --git a/Core/Encryptor.cs b/Core/Encryptor.cs index 71f5457..b6a1ac6 100644 --- a/Core/Encryptor.cs +++ b/Core/Encryptor.cs @@ -96,16 +96,12 @@ public static string EncryptString(string text, DatabaseControl db) encryptString = Convert.ToBase64String(baEncrypted); } - return db.ViewModel.Iterations + ":" + db.ViewModel.NumberOfEncryptionProcedures + ":" + encryptString; + return encryptString; } - public static string DecryptString(string text, DatabaseControl db) + public static string DecryptString(string text, DatabaseControl db, int iterations, int numberOfEncryptionProcedures) { - - string[] split = text.Split(':'); - int iterations = int.Parse(split[0]); - int numberOfEncryptionProcedures = int.Parse(split[1]); - string result = split[2]; + string result = text; byte[] baPwdHash = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(db.ViewModel.MasterPassword)); diff --git a/Core/Log.cs b/Core/Log.cs new file mode 100644 index 0000000..aa61611 --- /dev/null +++ b/Core/Log.cs @@ -0,0 +1,58 @@ +using System; +using System.IO; +using System.Text; + +namespace OlibKey.Core +{ + public class Log + { + private static readonly object Sync = new object(); + + public enum Type + { + Info, + Warning, + Error + } + + public static void WriteFatal(Exception ex) + { + try + { + string pathToLog = Path.Combine(AppDomain.CurrentDomain.BaseDirectory! , "Log"); + if(!Directory.Exists(pathToLog)) Directory.CreateDirectory(pathToLog); + + if (ex.TargetSite != null) + { + lock (Sync) + File.AppendAllText(Path.Combine(pathToLog, + $"{AppDomain.CurrentDomain.FriendlyName}_{DateTime.Now:dd.MM.yyy}.log"), + $"[{DateTime.Now:dd.MM.yyy HH:mm:ss.fff}] | Fatal | [{ex.TargetSite.DeclaringType}.{ex.TargetSite.Name}()] {ex}\r\n", + Encoding.UTF8); + } + } + catch + { + // ignored + } + } + public static void Write(string message, Type type) + { + try + { + string pathToLog = Path.Combine(AppDomain.CurrentDomain.BaseDirectory!, "Log"); + if(!Directory.Exists(pathToLog)) Directory.CreateDirectory(pathToLog); + + lock (Sync) + File.AppendAllText(Path.Combine(pathToLog, + $"{AppDomain.CurrentDomain.FriendlyName}_{DateTime.Now:dd.MM.yyy}.log"), + $"[{DateTime.Now:dd.MM.yyy HH:mm:ss.fff}] | {type} | {message}\r\n", Encoding.UTF8); + + } + catch + { + // ignored + } + } + } +} diff --git a/Core/PasswordGenerator.cs b/Core/PasswordGenerator.cs new file mode 100644 index 0000000..7da9e69 --- /dev/null +++ b/Core/PasswordGenerator.cs @@ -0,0 +1,45 @@ +namespace OlibKey.Core +{ + public static class PasswordGenerator + { + public static string RandomPassword() + { + const string lower = "abcdefghijklmnopqrstuvwxyz"; + const string upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const string number = "0123456789"; + const string special = @"~!@#$%^&*():;[]{}<>,.?/\|"; + string other = Program.Settings.GeneratorTextOther; + + string allowed = ""; + string password = ""; + if (Program.Settings.GeneratorAllowLowercase) allowed += lower; + if (Program.Settings.GeneratorAllowUppercase) allowed += upper; + if (Program.Settings.GeneratorAllowNumber) allowed += number; + if (Program.Settings.GeneratorAllowSpecial) allowed += special; + if (Program.Settings.GeneratorAllowUnderscore && password.IndexOfAny("_".ToCharArray()) == -1) + { + allowed += "_"; + password += "_"; + } + if (Program.Settings.GeneratorAllowOther) allowed += other; + int minChars = int.Parse(Program.Settings.GenerationCount); + int numChars = Encryptor.RandomInteger(minChars, minChars); + while (password.Length < numChars) + password += allowed.Substring(Encryptor.RandomInteger(0, allowed.Length - 1), 1); + password = RandomizeString(password); + return password; + } + private static string RandomizeString(string str) + { + string result = ""; + while (str.Length > 0) + { + int i = Encryptor.RandomInteger(0, str.Length - 1); + result += str.Substring(i, 1); + str = str.Remove(i, 1); + } + + return result; + } + } +} diff --git a/Core/PasswordUtils.cs b/Core/PasswordUtils.cs index 47b6e66..cb9e3b9 100644 --- a/Core/PasswordUtils.cs +++ b/Core/PasswordUtils.cs @@ -64,7 +64,7 @@ public static int CheckPasswordStrength(string password) {"[!,@#\\$%\\^&\\*?_~=;:'\"<>[]()~`\\\\|/]", 0.4}, {@"[¶©]", 0.5} }; - foreach ((string key, double value) in patterns) + foreach ((string key, double value) in patterns) if (Regex.Matches(password, key).Count > 0) multi2 += value; if (password.Length > 2) multi3 += 0; diff --git a/Core/SaveAndLoadDatabase.cs b/Core/SaveAndLoadDatabase.cs index a585664..6ccee50 100644 --- a/Core/SaveAndLoadDatabase.cs +++ b/Core/SaveAndLoadDatabase.cs @@ -7,14 +7,49 @@ namespace OlibKey.Core { public class SaveAndLoadDatabase { - public static Database LoadFiles(DatabaseControl db) => (Database)new XmlSerializer(typeof(Database)).Deserialize(new StringReader(Encryptor.DecryptString(File.ReadAllText(db.ViewModel.PathDatabase), db))); + public static Database LoadFiles(DatabaseControl db) + { + string s = File.ReadAllText(db.ViewModel.PathDatabase); + + string[] split = s.Split(':'); + int iterations = int.Parse(split[0]); + int numberOfEncryptionProcedures = int.Parse(split[1]); + string encryptString = split[2]; + + if (split.Length > 3) + { + bool useArchiving = bool.Parse(split[3]); + + if (useArchiving) + s = Compressing.Decompress(Encryptor.DecryptString(encryptString, db, iterations, numberOfEncryptionProcedures)); + + + db.ViewModel.UseCompression = useArchiving; + } + else + { + s = Encryptor.DecryptString(encryptString, db, iterations, numberOfEncryptionProcedures); + db.ViewModel.UseCompression = false; + } + + if (split.Length > 4) + db.ViewModel.UseTrash = bool.Parse(split[4]); + + return (Database)new XmlSerializer(typeof(Database)).Deserialize(new StringReader(s)); + } public static void SaveFiles(DatabaseControl db) { + string file = db.ViewModel.Iterations + ":" + db.ViewModel.NumberOfEncryptionProcedures + ":"; + using StringWriter writer = new StringWriter(); new XmlSerializer(typeof(Database)).Serialize(writer, db.ViewModel.Database); - File.WriteAllText(db.ViewModel.PathDatabase, Encryptor.EncryptString(writer.ToString(), db)); + string s = Encryptor.EncryptString(db.ViewModel.UseCompression ? Compressing.Compress(writer.ToString()) : writer.ToString(), db); + + file += s + ":" + db.ViewModel.UseCompression + ":" + db.ViewModel.UseTrash; + + File.WriteAllText(db.ViewModel.PathDatabase, file); } } } diff --git a/Core/SaveAndLoadSettings.cs b/Core/SaveAndLoadSettings.cs index 52c6857..222c24a 100644 --- a/Core/SaveAndLoadSettings.cs +++ b/Core/SaveAndLoadSettings.cs @@ -1,6 +1,7 @@ using OlibKey.Structures; using System; using System.IO; +using System.Security.Permissions; using System.Xml.Serialization; namespace OlibKey.Core @@ -18,11 +19,10 @@ public static Settings LoadSettings() return new Settings(); } } - public static void SaveSettings() { using StringWriter writer = new StringWriter(); - new XmlSerializer(typeof(Settings)).Serialize(writer, App.Settings); + new XmlSerializer(typeof(Settings)).Serialize(writer, Program.Settings); File.WriteAllText(AppDomain.CurrentDomain.BaseDirectory + "settings.xml", writer.ToString()); } diff --git a/ForRepository/ScreenProgram.png b/ForRepository/ScreenProgram.png index 4c8f177..c68cbab 100644 Binary files a/ForRepository/ScreenProgram.png and b/ForRepository/ScreenProgram.png differ diff --git a/ForRepository/screenshot1.png b/ForRepository/screenshot1.png new file mode 100644 index 0000000..9f0c5d0 Binary files /dev/null and b/ForRepository/screenshot1.png differ diff --git a/MainWindow.axaml b/MainWindow.axaml index 192c366..e7bde9e 100644 --- a/MainWindow.axaml +++ b/MainWindow.axaml @@ -10,7 +10,7 @@ Title="OlibKey" WindowStartupLocation="CenterScreen" Icon="avares://OlibKey/app.ico" - DragDrop.AllowDrop="{Binding IsActivateDnD}" + DragDrop.AllowDrop="True" Background="{DynamicResource ThemeWindowBackgroundBrush}" MinWidth="500" MinHeight="350"> @@ -25,6 +25,8 @@ + + @@ -42,6 +44,7 @@ + @@ -52,7 +55,8 @@ - + + @@ -69,7 +73,11 @@ - + + + + + @@ -102,6 +110,11 @@ + + + + + @@ -117,8 +130,17 @@ - + + + + + + + + + + diff --git a/MainWindow.axaml.cs b/MainWindow.axaml.cs index e7ab3bf..1eb89f9 100644 --- a/MainWindow.axaml.cs +++ b/MainWindow.axaml.cs @@ -10,8 +10,7 @@ namespace OlibKey { public class MainWindow : ReactiveWindow { - public ListBox MainWindowListBox; - private TextBlock _tbMessageStatusBar; + private TextBlock _tbMessageStatusBar; private TextBlock _tbReady; private TabControl _tabItems; @@ -21,19 +20,18 @@ private void InitializeComponent() { this.WhenActivated(disposables => { }); AvaloniaXamlLoader.Load(this); - - MainWindowListBox = this.FindControl("listBox"); + _tbMessageStatusBar = this.FindControl("tbMessageStatusBar"); _tabItems = this.FindControl("tabItems"); _tbReady = this.FindControl("tbReady"); Closing += App.MainWindowViewModel.ProgramClosing; - Opened += (s, e) => App.MainWindowViewModel.Loading(this); + Opened += (_, __) => App.MainWindowViewModel.Loading(); _tabItems.SelectionChanged += App.MainWindowViewModel.TabItemsSelectionChanged; - Activated += (s, e) => { App.Autoblock.Stop(); }; - Deactivated += (s, e) => { if (App.Settings.AutoblockEnabled) App.Autoblock.Start(); }; + Activated += (_, __) => { App.Autoblock.Stop(); }; + Deactivated += (_, __) => { if (Program.Settings.AutoblockEnabled) App.Autoblock.Start(); }; SetupDnd(); } @@ -42,13 +40,13 @@ private void SetupDnd() { static void DragOver(object sender, DragEventArgs e) { - e.DragEffects &= (DragDropEffects.Copy | DragDropEffects.Link); + e.DragEffects &= DragDropEffects.Copy | DragDropEffects.Link; if (!e.Data.Contains(DataFormats.FileNames)) e.DragEffects = DragDropEffects.None; } static void Drop(object sender, DragEventArgs e) { - if (e.Data.Contains(DataFormats.FileNames)) App.MainWindowViewModel.OpenStorageDnD(e.Data.GetFileNames().ToList()); + if (e.Data.Contains(DataFormats.FileNames)) App.MainWindowViewModel.OpenStorageDnD(e.Data.GetFileNames().ToArray()); } AddHandler(DragDrop.DropEvent, Drop); @@ -58,11 +56,22 @@ static void Drop(object sender, DragEventArgs e) public async void MessageStatusBar(string message) { _tbMessageStatusBar.IsVisible = true; - _tbReady.IsVisible = false; _tbMessageStatusBar.Text = message; - await Task.Delay(App.Settings.MessageDuration * 1000); + _tbReady.IsVisible = false; + await Task.Delay(Program.Settings.MessageDuration * 1000); _tbMessageStatusBar.IsVisible = false; _tbReady.IsVisible = true; } + public void PermanentMessageStatusBar(string message) + { + _tbMessageStatusBar.IsVisible = true; + _tbMessageStatusBar.Text = message; + _tbReady.IsVisible = false; + } + public void ResetMessageStatusBar() + { + _tbMessageStatusBar.IsVisible = false; + _tbReady.IsVisible = true; + } } } \ No newline at end of file diff --git a/MainWindowViewModel.cs b/MainWindowViewModel.cs index 803ac70..4ff0a50 100644 --- a/MainWindowViewModel.cs +++ b/MainWindowViewModel.cs @@ -12,471 +12,454 @@ using System; using System.Collections.Generic; using Avalonia; +using System.Threading.Tasks; namespace OlibKey { - public class MainWindowViewModel : ReactiveObject - { - private bool _isUnlockDatabase; - private bool _isLockDatabase; - private bool _isActivateDnD; - - private int _selectedTabIndex; - private int _countLogins; - - private ObservableCollection _tabItems = new ObservableCollection(); - - #region ReactiveCommands - - private ReactiveCommand ExitProgramCommand { get; } - private ReactiveCommand CreateLoginCommand { get; } - private ReactiveCommand CreateDatabaseCommand { get; } - private ReactiveCommand SaveDatabaseCommand { get; } - private ReactiveCommand UnlockDatabaseCommand { get; } - private ReactiveCommand LockDatabaseCommand { get; } - private ReactiveCommand OpenDatabaseCommand { get; } - private ReactiveCommand ShowSearchWindowCommand { get; } - private ReactiveCommand ChangeMasterPasswordCommand { get; } - private ReactiveCommand OpenPasswordGeneratorWindowCommand { get; } - private ReactiveCommand OpenAboutWindowCommand { get; } - private ReactiveCommand OpenSettingsWindowCommand { get; } - private ReactiveCommand CheckUpdateCommand { get; } - private ReactiveCommand LockAllDatabasesCommand { get; } - private ReactiveCommand SaveAllDatabasesCommand { get; } - private ReactiveCommand UnlockAllDatabasesCommand { get; } - - #endregion - - #region Propertie's - - public ObservableCollection TabItems - { - get => _tabItems; - set => this.RaiseAndSetIfChanged(ref _tabItems, value); - } - public bool IsLockDatabase - { - get => _isLockDatabase; - set => this.RaiseAndSetIfChanged(ref _isLockDatabase, value); - } - public bool IsUnlockDatabase - { - get => _isUnlockDatabase; - set => this.RaiseAndSetIfChanged(ref _isUnlockDatabase, value); - } - private int SelectedTabIndex - { - get => _selectedTabIndex; - set => this.RaiseAndSetIfChanged(ref _selectedTabIndex, value); - } - public int CountLogins - { - get => _countLogins; - set => this.RaiseAndSetIfChanged(ref _countLogins, value); - } - public bool IsActivateDnD - { - get => _isActivateDnD; - set => this.RaiseAndSetIfChanged(ref _isActivateDnD, value); - } - public DatabaseControl SelectedTabItem { get { try { return (DatabaseControl)TabItems[SelectedTabIndex].Content; } catch { return null; } } } - public DatabaseTabHeader SelectedTabItemHeader { get { try { return (DatabaseTabHeader)TabItems[SelectedTabIndex].Header; } catch { return null; } } } - public List OpenStorages { get; set; } - - #endregion - - public MainWindowViewModel() - { - ExitProgramCommand = ReactiveCommand.Create(ExitApplication); - CreateLoginCommand = ReactiveCommand.Create(CreateLogin); - OpenSettingsWindowCommand = ReactiveCommand.Create(OpenSettingsWindow); - CreateDatabaseCommand = ReactiveCommand.Create(CreateDatabase); - SaveDatabaseCommand = ReactiveCommand.Create(() => SaveDatabase(SelectedTabItem)); - UnlockDatabaseCommand = ReactiveCommand.Create(UnlockDatabase); - LockDatabaseCommand = ReactiveCommand.Create(LockDatabase); - OpenDatabaseCommand = ReactiveCommand.Create(OpenDatabase); - CheckUpdateCommand = ReactiveCommand.Create(CheckUpdate); - ShowSearchWindowCommand = ReactiveCommand.Create(ShowSearchWindow); - OpenPasswordGeneratorWindowCommand = ReactiveCommand.Create(() => { new PasswordGeneratorWindow().ShowDialog(App.MainWindow); }); - OpenAboutWindowCommand = ReactiveCommand.Create(() => { new AboutWindow().ShowDialog(App.MainWindow); }); - ChangeMasterPasswordCommand = ReactiveCommand.Create(ChangeMasterPassword); - LockAllDatabasesCommand = ReactiveCommand.Create(LockAllDatabases); - SaveAllDatabasesCommand = ReactiveCommand.Create(SaveAllDatabases); - UnlockAllDatabasesCommand = ReactiveCommand.Create(UnlockAllDatabases); - - App.Autoblock.Tick += AutoblockStorage; - } - - public async void Loading(MainWindow mainWindow) - { - foreach (var item in OpenStorages.Where(item => Path.GetExtension(item) == ".olib")) - { - App.Settings.PathDatabase = item; - - string id = Guid.NewGuid().ToString("N"); - - DatabaseTabHeader tabHeader = new DatabaseTabHeader(id, Path.GetFileNameWithoutExtension(App.Settings.PathDatabase)) - { - CloseTab = CloseTab, - iLock = { IsVisible = true }, - iUnlock = { IsVisible = false } - }; - - DatabaseControl db = new DatabaseControl - { - ViewModel = - { - IsLockDatabase = true, - IsUnlockDatabase = false, - PathDatabase = App.Settings.PathDatabase, - TabID = id - } - }; - - TabItems.Add(new TabItem { Header = tabHeader, Content = db }); - - RequireMasterPasswordWindow passwordWindow = new RequireMasterPasswordWindow - { - LoadStorageCallback = LoadDatabase, - databaseControl = db, - databaseTabHeader = tabHeader, - tbNameStorage = { Text = Path.GetFileNameWithoutExtension(App.Settings.PathDatabase) } - }; - IsActivateDnD = false; - await passwordWindow.ShowDialog(App.MainWindow); - IsActivateDnD = true; - } - - if (OpenStorages.Count > 0) - { - OpenStorages = null; - return; - } - - if (!string.IsNullOrEmpty(App.Settings.PathDatabase) && File.Exists(App.Settings.PathDatabase)) - { - string id = Guid.NewGuid().ToString("N"); - - DatabaseTabHeader tabHeader = new DatabaseTabHeader(id, Path.GetFileNameWithoutExtension(App.Settings.PathDatabase)) - { - CloseTab = CloseTab, - iLock = { IsVisible = true }, - iUnlock = { IsVisible = false } - }; - - DatabaseControl db = new DatabaseControl - { - ViewModel = - { - IsLockDatabase = true, - IsUnlockDatabase = false, - PathDatabase = App.Settings.PathDatabase, - TabID = id - } - }; - - TabItems.Add(new TabItem { Header = tabHeader, Content = db }); - - RequireMasterPasswordWindow passwordWindow = new RequireMasterPasswordWindow - { - LoadStorageCallback = LoadDatabase, - databaseControl = db, - databaseTabHeader = tabHeader, - tbNameStorage = { Text = Path.GetFileNameWithoutExtension(App.Settings.PathDatabase) } - }; - IsActivateDnD = false; - await passwordWindow.ShowDialog(mainWindow); - IsActivateDnD = true; - } - } - public async void OpenStorageDnD(List files) - { - foreach (var item in files.Where(item => Path.GetExtension(item) == ".olib").Where(item => TabItems.All(i => ((DatabaseControl)i.Content).ViewModel.PathDatabase != item))) - { - App.Settings.PathDatabase = item; - - string id = Guid.NewGuid().ToString("N"); - - DatabaseTabHeader tabHeader = new DatabaseTabHeader(id, Path.GetFileNameWithoutExtension(App.Settings.PathDatabase)) - { - CloseTab = CloseTab, - iLock = { IsVisible = true }, - iUnlock = { IsVisible = false } - }; - - DatabaseControl db = new DatabaseControl - { - ViewModel = - { - IsLockDatabase = true, - IsUnlockDatabase = false, - PathDatabase = App.Settings.PathDatabase, - TabID = id - } - }; - - TabItems.Add(new TabItem { Header = tabHeader, Content = db }); - - RequireMasterPasswordWindow passwordWindow = new RequireMasterPasswordWindow - { - LoadStorageCallback = LoadDatabase, - databaseControl = db, - databaseTabHeader = tabHeader, - tbNameStorage = { Text = Path.GetFileNameWithoutExtension(App.Settings.PathDatabase) } - }; - IsActivateDnD = false; - await passwordWindow.ShowDialog(App.MainWindow); - IsActivateDnD = true; - } - - App.MainWindow.MessageStatusBar((string)Application.Current.FindResource("Not6")); - } - public void AutoblockStorage(object sender, EventArgs e) - { - foreach (TabItem item in TabItems) - { - DatabaseControl db = (DatabaseControl)item.Content; - DatabaseTabHeader dbHeader = (DatabaseTabHeader)item.Header; - - if (db.ViewModel.IsUnlockDatabase) - { - if (db.ViewModel.LoginList.Any(login => login.LoginItem.IsReminderActive)) continue; - - SaveDatabase(db); - db.ViewModel.ClearLoginsList(); - IsUnlockDatabase = db.ViewModel.IsUnlockDatabase = dbHeader.iUnlock.IsVisible = false; - IsLockDatabase = db.ViewModel.IsLockDatabase = dbHeader.iLock.IsVisible = true; - db.ViewModel.Router.Navigate.Execute(new StartPageViewModel(db.ViewModel)); - } - } - App.Autoblock.Stop(); - } - public void ProgramClosing(object sender, System.ComponentModel.CancelEventArgs e) - { - App.Autosave.Stop(); - SaveSettings(); - foreach (TabItem item in TabItems) SaveDatabase((DatabaseControl)item.Content); - } - public void SaveDatabase(DatabaseControl db) - { - if (db == null || db.ViewModel.IsLockDatabase || !db.ViewModel.IsUnlockDatabase) return; - if (db.ViewModel.PathDatabase != null) - { - db.ViewModel.Database.Logins = db.ViewModel.LoginList.Select(item => item.LoginItem).ToList(); - - SaveAndLoadDatabase.SaveFiles(db); - App.MainWindow.MessageStatusBar((string)Application.Current.FindResource("Not4") + $" {Path.GetFileNameWithoutExtension(db.ViewModel.PathDatabase)}"); - } - for (int i = 0; i < db.ViewModel.Router.NavigationStack.Count - 1; i++) - { - IRoutableViewModel item = db.ViewModel.Router.NavigationStack[i]; - db.ViewModel.Router.NavigationStack.Remove(item); - } - } - public void TabItemsSelectionChanged(object sender, SelectionChangedEventArgs e) - { - if (SelectedTabItem != null) - { - IsUnlockDatabase = SelectedTabItem.ViewModel.IsUnlockDatabase; - IsLockDatabase = SelectedTabItem.ViewModel.IsLockDatabase; - CountLogins = SelectedTabItem.ViewModel.LoginList.Count; - } - else - { - IsUnlockDatabase = false; - IsLockDatabase = false; - } - - } - public void CloseTab(string tabID) - { - foreach (TabItem item in TabItems.Where(item => ((DatabaseControl)item.Content).ViewModel.TabID == tabID)) - { - SaveDatabase((DatabaseControl)item.Content); - - TabItems.Remove(item); - break; - } - } - private async void UnlockDatabase() - { - if (SelectedTabItem == null || SelectedTabItem.ViewModel.IsUnlockDatabase) return; - - RequireMasterPasswordWindow passwordWindow = new RequireMasterPasswordWindow - { - LoadStorageCallback = LoadDatabase, - databaseControl = SelectedTabItem, - databaseTabHeader = SelectedTabItemHeader, - tbNameStorage = { Text = Path.GetFileNameWithoutExtension(SelectedTabItem.ViewModel.PathDatabase) } - }; - IsActivateDnD = false; - await passwordWindow.ShowDialog(App.MainWindow); - IsActivateDnD = true; - } - private async void UnlockAllDatabases() - { - foreach (var item in TabItems.Where(item => ((DatabaseControl)item.Content).ViewModel.IsLockDatabase)) - { - DatabaseControl db = (DatabaseControl)item.Content; - DatabaseTabHeader dbHeader = (DatabaseTabHeader)item.Header; - RequireMasterPasswordWindow passwordWindow = new RequireMasterPasswordWindow - { - LoadStorageCallback = LoadDatabase, - databaseControl = db, - databaseTabHeader = dbHeader, - tbNameStorage = { Text = Path.GetFileNameWithoutExtension(db.ViewModel.PathDatabase) } - }; - IsActivateDnD = false; - await passwordWindow.ShowDialog(App.MainWindow); - IsActivateDnD = true; - } - App.MainWindow.MessageStatusBar((string)Application.Current.FindResource("Not8")); - } - private void LockDatabase() - { - if (SelectedTabItem == null || SelectedTabItem.ViewModel.IsLockDatabase) return; - - SaveDatabase(SelectedTabItem); - SelectedTabItem.ViewModel.ClearLoginsList(); - IsUnlockDatabase = SelectedTabItem.ViewModel.IsUnlockDatabase = false; - IsLockDatabase = SelectedTabItem.ViewModel.IsLockDatabase = true; - SelectedTabItemHeader.iLock.IsVisible = true; - SelectedTabItemHeader.iUnlock.IsVisible = false; - SelectedTabItem.ViewModel.Router.Navigate.Execute(new StartPageViewModel(SelectedTabItem.ViewModel)); - } - private void LockAllDatabases() - { - foreach (TabItem item in TabItems) - { - DatabaseControl db = (DatabaseControl)item.Content; - DatabaseTabHeader dbHeader = (DatabaseTabHeader)item.Header; - - SaveDatabase(db); - db.ViewModel.ClearLoginsList(); - IsUnlockDatabase = db.ViewModel.IsUnlockDatabase = dbHeader.iUnlock.IsVisible = false; - IsLockDatabase = db.ViewModel.IsLockDatabase = dbHeader.iLock.IsVisible = true; - db.ViewModel.Router.Navigate.Execute(new StartPageViewModel(db.ViewModel)); - } - App.MainWindow.MessageStatusBar((string)Application.Current.FindResource("Not7")); - } - private async void OpenDatabase() - { - OpenFileDialog dialog = new OpenFileDialog { AllowMultiple = true }; - dialog.Filters.Add(new FileDialogFilter { Name = (string)Application.Current.FindResource("FileOlib"), Extensions = { "olib" } }); - List files = (await dialog.ShowAsync(App.MainWindow)).ToList(); - - if (files.Count == 0) return; - - foreach (var file in files.Where(file => TabItems.All(i => ((DatabaseControl)i.Content).ViewModel.PathDatabase != file))) - { - App.Settings.PathDatabase = file; - - string id = Guid.NewGuid().ToString("N"); - - DatabaseControl db = new DatabaseControl - { - ViewModel = - { - Database = new Database(), - IsLockDatabase = true, - IsUnlockDatabase = false, - PathDatabase = file, - TabID = id - } - }; - DatabaseTabHeader tabHeader = new DatabaseTabHeader(id, Path.GetFileNameWithoutExtension(App.Settings.PathDatabase)) - { - CloseTab = CloseTab, - iLock = { IsVisible = true }, - iUnlock = { IsVisible = false } - }; - TabItems.Add(new TabItem { Header = tabHeader, Content = db }); - - RequireMasterPasswordWindow requireMaster = new RequireMasterPasswordWindow { LoadStorageCallback = LoadDatabase, databaseControl = db, databaseTabHeader = tabHeader, tbNameStorage = { Text = Path.GetFileNameWithoutExtension(App.Settings.PathDatabase) } }; - IsActivateDnD = false; - await requireMaster.ShowDialog(App.MainWindow); - IsActivateDnD = true; - } - } - private void CreateLogin() - { - if (SelectedTabItem == null || SelectedTabItem.ViewModel.IsLockDatabase) return; - - SelectedTabItem.ViewModel.SelectedIndex = -1; - - SelectedTabItem.ViewModel.Router.Navigate.Execute(new CreateLoginPageViewModel(SelectedTabItem.ViewModel.Database, SelectedTabItem.ViewModel) - { - BackPageCallback = SelectedTabItem.ViewModel.StartPage, - CreateLoginCallback = SelectedTabItem.ViewModel.AddLogin - }); - } - private void LoadDatabase(DatabaseControl db, DatabaseTabHeader dbHeader) - { - db.ViewModel.Database = SaveAndLoadDatabase.LoadFiles(db); - foreach (Login logins in db.ViewModel.Database.Logins) db.ViewModel.AddLogin(logins); - db.ViewModel.IsLockDatabase = dbHeader.iLock.IsVisible = false; - db.ViewModel.IsUnlockDatabase = dbHeader.iUnlock.IsVisible = true; - - if (Equals(SelectedTabItem, db)) - { - IsLockDatabase = false; - IsUnlockDatabase = true; - } - - App.MainWindow.MessageStatusBar((string)Application.Current.FindResource("Not9") + $" {Path.GetFileNameWithoutExtension(db.ViewModel.PathDatabase)}"); - } - private async void CreateDatabase() - { - CreateDatabaseWindow window = new CreateDatabaseWindow(); - if (await window.ShowDialog(App.MainWindow)) - { - App.Settings.PathDatabase = window.TbPathDatabase.Text; - - string id = Guid.NewGuid().ToString("N"); - - DatabaseTabHeader tabHeader = new DatabaseTabHeader(id, Path.GetFileNameWithoutExtension(App.Settings.PathDatabase)) - { - CloseTab = CloseTab, - iLock = { IsVisible = false }, - iUnlock = { IsVisible = true } - }; - - DatabaseControl db = new DatabaseControl - { - ViewModel = - { - Database = new Database { Folders = new List(), Logins = new List() }, - MasterPassword = window.TbPassword.Text, - Iterations = int.Parse(window.TbIteration.Text), - NumberOfEncryptionProcedures = int.Parse(window.TbNumberOfEncryptionProcedures.Text), - IsLockDatabase = false, - IsUnlockDatabase = true, - PathDatabase = window.TbPathDatabase.Text, - TabID = id - } - }; - - TabItems.Add(new TabItem { Header = tabHeader, Content = db }); - - SaveDatabase(db); - App.MainWindow.MessageStatusBar((string)Application.Current.FindResource("Not3") + $" {Path.GetFileNameWithoutExtension(App.Settings.PathDatabase)}"); - } - } - private void ShowSearchWindow() - { - if (SelectedTabItem == null || SelectedTabItem.ViewModel.IsLockDatabase) return; - App.SearchWindow = new SearchWindow(); - foreach (Folder folder in SelectedTabItem.ViewModel.Database.Folders) App.SearchWindow.SearchViewModel.AddFolder(folder); - App.SearchWindow.ShowDialog(App.MainWindow); - } - private void SaveAllDatabases() - { - foreach (TabItem item in TabItems) SaveDatabase((DatabaseControl)item.Content); - } - private void OpenSettingsWindow() => new SettingsWindow().ShowDialog(App.MainWindow); - private void CheckUpdate() => App.CheckUpdate(true); - private void ChangeMasterPassword() => new ChangeMasterPasswordWindow().ShowDialog(App.MainWindow); - private void ExitApplication() => App.MainWindow.Close(); - private void SaveSettings() => SaveAndLoadSettings.SaveSettings(); - } + public class MainWindowViewModel : ReactiveObject + { + private bool _isUnlockDatabase; + private bool _isLockDatabase; + + private int _selectedTabIndex; + private int _countLogins; + + private ChangeMasterPasswordWindow _windowChangeMasterPassword; + private SettingsWindow _settingsWindow; + public PasswordGeneratorWindow PasswordGenerator; + public CheckingWeakPasswordsWindow CheckingWindow; + public TrashWindow TrashWindow; + + private ObservableCollection _tabItems = new ObservableCollection(); + + #region ReactiveCommand's + + private ReactiveCommand ExitProgramCommand { get; } + private ReactiveCommand CreateLoginCommand { get; } + private ReactiveCommand CreateDatabaseCommand { get; } + private ReactiveCommand SaveDatabaseCommand { get; } + private ReactiveCommand UnlockDatabaseCommand { get; } + private ReactiveCommand LockDatabaseCommand { get; } + private ReactiveCommand OpenDatabaseCommand { get; } + private ReactiveCommand ShowSearchWindowCommand { get; } + private ReactiveCommand ChangeMasterPasswordCommand { get; } + private ReactiveCommand OpenPasswordGeneratorWindowCommand { get; } + private ReactiveCommand OpenAboutWindowCommand { get; } + private ReactiveCommand OpenSettingsWindowCommand { get; } + private ReactiveCommand CheckUpdateCommand { get; } + private ReactiveCommand LockAllDatabasesCommand { get; } + private ReactiveCommand SaveAllDatabasesCommand { get; } + private ReactiveCommand UnlockAllDatabasesCommand { get; } + private ReactiveCommand OpenCheckingWeakPasswordsWindowCommand { get; } + private ReactiveCommand ClearGCCommand { get; } + private ReactiveCommand OpenTrashWindowCommand { get; } + + #endregion + + #region Propertie's + + public ObservableCollection TabItems + { + get => _tabItems; + set => this.RaiseAndSetIfChanged(ref _tabItems, value); + } + private int SelectedTabIndex + { + get => _selectedTabIndex; + set => this.RaiseAndSetIfChanged(ref _selectedTabIndex, value); + } + public int CountLogins + { + get => _countLogins; + set => this.RaiseAndSetIfChanged(ref _countLogins, value); + } + public bool IsUnlockDatabase + { + get => _isUnlockDatabase; + set => this.RaiseAndSetIfChanged(ref _isUnlockDatabase, value); + } + private bool IsLockDatabase + { + get => _isLockDatabase; + set => this.RaiseAndSetIfChanged(ref _isLockDatabase, value); + } + public DatabaseControl SelectedTabItem { get { try { return (DatabaseControl)TabItems[SelectedTabIndex].Content; } catch { return null; } } } + private DatabaseTabHeader SelectedTabItemHeader { get { try { return (DatabaseTabHeader)TabItems[SelectedTabIndex].Header; } catch { return null; } } } + public List OpenStorages { get; set; } + + #endregion + + public MainWindowViewModel() + { + ExitProgramCommand = ReactiveCommand.Create(ExitApplication); + CreateLoginCommand = ReactiveCommand.Create(CreateLogin); + OpenSettingsWindowCommand = ReactiveCommand.Create(OpenSettingsWindow); + CreateDatabaseCommand = ReactiveCommand.Create(CreateDatabase); + SaveDatabaseCommand = ReactiveCommand.Create(() => SaveDatabase(SelectedTabItem)); + UnlockDatabaseCommand = ReactiveCommand.Create(UnlockDatabase); + LockDatabaseCommand = ReactiveCommand.Create(LockDatabase); + OpenDatabaseCommand = ReactiveCommand.Create(OpenDatabase); + CheckUpdateCommand = ReactiveCommand.Create(CheckUpdate); + ShowSearchWindowCommand = ReactiveCommand.Create(ShowSearchWindow); + OpenPasswordGeneratorWindowCommand = ReactiveCommand.Create(() => { new PasswordGeneratorWindow().ShowDialog(App.MainWindow); }); + OpenAboutWindowCommand = ReactiveCommand.Create(() => { new AboutWindow().ShowDialog(App.MainWindow); }); + ChangeMasterPasswordCommand = ReactiveCommand.Create(ChangeMasterPassword); + LockAllDatabasesCommand = ReactiveCommand.Create(LockAllDatabases); + SaveAllDatabasesCommand = ReactiveCommand.Create(SaveAllDatabases); + UnlockAllDatabasesCommand = ReactiveCommand.Create(UnlockAllDatabases); + OpenCheckingWeakPasswordsWindowCommand = ReactiveCommand.Create(OpenCheckingWeakPasswordsWindow); + ClearGCCommand = ReactiveCommand.Create(ClearGC); + OpenTrashWindowCommand = ReactiveCommand.Create(OpenTrashWindow); + + App.Autoblock.Tick += AutoblockStorage; + } + + public void Loading() + { + for (int i = 0; i < OpenStorages.Count; i++) + { + string item = OpenStorages[i]; + if (Path.GetExtension(item) == ".olib") + CreateTab(Program.Settings.PathDatabase = item, true, false); + } + + if (OpenStorages.Count > 0) + { + OpenStorages = null; + return; + } + + if (!string.IsNullOrEmpty(Program.Settings.PathDatabase) && File.Exists(Program.Settings.PathDatabase)) + CreateTab(Program.Settings.PathDatabase, true, false); + } + public void OpenStorageDnD(IEnumerable files) + { + foreach (string item in files.Where(item => Path.GetExtension(item) == ".olib").Where(item => + TabItems.All(i => ((DatabaseControl)i.Content).ViewModel.PathDatabase != item))) + CreateTab(Program.Settings.PathDatabase = item, true, false); + + App.MainWindow.MessageStatusBar((string)Application.Current.FindResource("Not6")); + } + public void ProgramClosing(object sender, System.ComponentModel.CancelEventArgs e) + { + SaveSettings(); + for (int index = 0; index < TabItems.Count; index++) SaveDatabase((DatabaseControl)TabItems[index].Content); + } + public void SaveDatabase(DatabaseControl db) + { + if (db == null || db.ViewModel.IsLockDatabase || !db.ViewModel.IsUnlockDatabase) return; + if (db.ViewModel.PathDatabase != null) + { + db.ViewModel.Database.Logins = db.ViewModel.LoginList.Select(item => item.LoginItem).ToList(); + SaveAndLoadDatabase.SaveFiles(db); + App.MainWindow.MessageStatusBar((string)Application.Current.FindResource("Not4") + $" {Path.GetFileNameWithoutExtension(db.ViewModel.PathDatabase)}"); + } + for (int i = 0; i < db.ViewModel.Router.NavigationStack.Count - 1; i++) + db.ViewModel.Router.NavigationStack.Remove(db.ViewModel.Router.NavigationStack[i]); + } + public void TabItemsSelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (SelectedTabItem != null) + { + IsUnlockDatabase = SelectedTabItem.ViewModel.IsUnlockDatabase; + IsLockDatabase = SelectedTabItem.ViewModel.IsLockDatabase; + CountLogins = SelectedTabItem.ViewModel.LoginList.Count; + } + else + { + IsUnlockDatabase = false; + IsLockDatabase = false; + } + } + private void CreateTab(string path, bool isLockDatabase, bool isUnlockDatabase) + { + string id = Guid.NewGuid().ToString("N"); + + DatabaseControl db = new DatabaseControl + { + ViewModel = + { + Database = new Database(), + IsLockDatabase = isLockDatabase, + IsUnlockDatabase = isUnlockDatabase, + PathDatabase = path, + TabID = id + } + }; + DatabaseTabHeader tabHeader = new DatabaseTabHeader(id, Path.GetFileNameWithoutExtension(Program.Settings.PathDatabase)) + { + CloseTab = CloseTab, + iLock = { IsVisible = true }, + iUnlock = { IsVisible = false } + }; + + TabItems.Add(new TabItem { Header = tabHeader, Content = db }); + + new RequireMasterPasswordWindow + { + LoadStorageCallback = LoadDatabase, + databaseControl = db, + databaseTabHeader = tabHeader, + tbNameStorage = { Text = Path.GetFileNameWithoutExtension(Program.Settings.PathDatabase) } + }.ShowDialog(App.MainWindow); + } + private void OpenCheckingWeakPasswordsWindow() + { + if (SelectedTabItem == null || SelectedTabItem.ViewModel.IsLockDatabase) return; + CheckingWindow = new CheckingWeakPasswordsWindow(); + CheckingWindow.ShowDialog(App.MainWindow); + + SelectedTabItem.ViewModel.SelectedIndex = -1; + SelectedTabItem.ViewModel.Router.Navigate.Execute(new StartPageViewModel()); + } + private void CloseTab(string tabID) + { + for (int i = 0; i < TabItems.Count; i++) + { + DatabaseControl item = (DatabaseControl)TabItems[i].Content; + if (item.ViewModel.TabID == tabID) + { + SaveDatabase(item); + + TabItems.Remove(TabItems[i]); + break; + } + } + } + private void AutoblockStorage(object sender, EventArgs e) + { + App.Autoblock.Stop(); + + App.SearchWindow?.Close(); + _windowChangeMasterPassword?.Close(); + _settingsWindow?.Close(); + PasswordGenerator?.Close(); + CheckingWindow?.Close(); + TrashWindow?.Close(); + + for (int index = 0; index < TabItems.Count; index++) + { + DatabaseControl control = (DatabaseControl)TabItems[index].Content; + DatabaseTabHeader header = (DatabaseTabHeader)TabItems[index].Header; + + if (control.ViewModel.IsUnlockDatabase && header != null) + { + if (control.ViewModel.LoginList.Any(login => login.LoginItem.IsReminderActive)) continue; + + SaveDatabase(control); + control.ViewModel.ClearLoginsList(); + IsUnlockDatabase = control.ViewModel.IsUnlockDatabase = header.iUnlock.IsVisible = false; + IsLockDatabase = control.ViewModel.IsLockDatabase = header.iLock.IsVisible = true; + control.ViewModel.Router.Navigate.Execute(new StartPageViewModel(control.ViewModel)); + } + } + } + private async void UnlockDatabase() + { + if (SelectedTabItem == null || SelectedTabItem.ViewModel.IsUnlockDatabase) return; + + await new RequireMasterPasswordWindow + { + LoadStorageCallback = LoadDatabase, + databaseControl = SelectedTabItem, + databaseTabHeader = SelectedTabItemHeader, + tbNameStorage = { Text = Path.GetFileNameWithoutExtension(SelectedTabItem.ViewModel.PathDatabase) } + }.ShowDialog(App.MainWindow); + } + private async void UnlockAllDatabases() + { + for (int i = 0; i < TabItems.Count; i++) + { + TabItem item = TabItems[i]; + if (((DatabaseControl)item.Content).ViewModel.IsLockDatabase) + { + await new RequireMasterPasswordWindow + { + LoadStorageCallback = LoadDatabase, + databaseControl = (DatabaseControl)item.Content, + databaseTabHeader = (DatabaseTabHeader)item.Header, + tbNameStorage = { Text = Path.GetFileNameWithoutExtension(((DatabaseControl)item.Content).ViewModel.PathDatabase) } + }.ShowDialog(App.MainWindow); + } + } + + App.MainWindow.MessageStatusBar((string)Application.Current.FindResource("Not8")); + } + private void LockDatabase() + { + if (SelectedTabItem == null || SelectedTabItem.ViewModel.IsLockDatabase) return; + + SaveDatabase(SelectedTabItem); + SelectedTabItem.ViewModel.ClearLoginsList(); + IsUnlockDatabase = SelectedTabItem.ViewModel.IsUnlockDatabase = SelectedTabItemHeader.iUnlock.IsVisible = false; + IsLockDatabase = SelectedTabItem.ViewModel.IsLockDatabase = SelectedTabItemHeader.iLock.IsVisible = true; + SelectedTabItem.ViewModel.Router.Navigate.Execute(new StartPageViewModel(SelectedTabItem.ViewModel)); + } + private void LockAllDatabases() + { + for (int index = 0; index < TabItems.Count; index++) + { + DatabaseControl control = (DatabaseControl)TabItems[index].Content; + DatabaseTabHeader header = (DatabaseTabHeader)TabItems[index].Header; + + SaveDatabase(control); + if (header != null) + { + control.ViewModel.ClearLoginsList(); + IsUnlockDatabase = control.ViewModel.IsUnlockDatabase = header.iUnlock.IsVisible = false; + IsLockDatabase = control.ViewModel.IsLockDatabase = header.iLock.IsVisible = true; + control.ViewModel.Router.Navigate.Execute(new StartPageViewModel(control.ViewModel)); + } + } + + App.MainWindow.MessageStatusBar((string)Application.Current.FindResource("Not7")); + } + private async void OpenDatabase() + { + try + { + OpenFileDialog dialog = new OpenFileDialog { AllowMultiple = true }; + dialog.Filters.Add(new FileDialogFilter { Name = (string)Application.Current.FindResource("FileOlib"), Extensions = { "olib" } }); + List files = (await dialog.ShowAsync(App.MainWindow)).ToList(); + + if (files.Count == 0) return; + + foreach (string file in files.Where(file => + TabItems.All(i => ((DatabaseControl)i.Content).ViewModel.PathDatabase != file))) + CreateTab(Program.Settings.PathDatabase = file, true, false); + } + catch + { + // ignored + } + } + private void CreateLogin() + { + if (SelectedTabItem == null || SelectedTabItem.ViewModel.IsLockDatabase) return; + + SelectedTabItem.ViewModel.SelectedIndex = -1; + + SelectedTabItem.ViewModel.Router.Navigate.Execute(new CreateLoginPageViewModel(SelectedTabItem.ViewModel.Database, SelectedTabItem.ViewModel) + { + BackPageCallback = SelectedTabItem.ViewModel.StartPage, + CreateLoginCallback = SelectedTabItem.ViewModel.AddLogin + }); + } + private void LoadDatabase(DatabaseControl db, DatabaseTabHeader dbHeader) + { + db.ViewModel.Database = SaveAndLoadDatabase.LoadFiles(db); + for (int index = 0; index < db.ViewModel.Database.Logins.Count; index++) + db.ViewModel.AddLogin(db.ViewModel.Database.Logins[index]); + + db.ViewModel.IsLockDatabase = dbHeader.iLock.IsVisible = false; + db.ViewModel.IsUnlockDatabase = dbHeader.iUnlock.IsVisible = true; + + if (Equals(SelectedTabItem, db)) + { + IsLockDatabase = false; + IsUnlockDatabase = true; + } + + if (Program.Settings.AutoRemoveItemsTrash) + { + if (db.ViewModel.Database.Trash != null) + { + for (int i = db.ViewModel.Database.Trash.Logins.Count - 1; i > -1; i--) + if (DateTime.Parse(db.ViewModel.Database.Trash.Logins[i].DeleteDate, System.Threading.Thread.CurrentThread.CurrentUICulture).AddDays(Program.Settings.DaysAfterDeletion) <= DateTime.Now) + db.ViewModel.Database.Trash.Logins.Remove(db.ViewModel.Database.Trash.Logins[i]); + + for (int i = db.ViewModel.Database.Trash.Folders.Count - 1; i > -1; i--) + if (DateTime.Parse(db.ViewModel.Database.Trash.Folders[i].DeleteDate, System.Threading.Thread.CurrentThread.CurrentUICulture).AddDays(Program.Settings.DaysAfterDeletion) <= DateTime.Now) + db.ViewModel.Database.Trash.Folders.Remove(db.ViewModel.Database.Trash.Folders[i]); + } + } + + App.MainWindow.MessageStatusBar((string)Application.Current.FindResource("Not9") + $" {Path.GetFileNameWithoutExtension(db.ViewModel.PathDatabase)}"); + } + private async void CreateDatabase() + { + CreateDatabaseWindow window = new CreateDatabaseWindow(); + if (await window.ShowDialog(App.MainWindow)) + { + string id = Guid.NewGuid().ToString("N"); + + DatabaseTabHeader tabHeader = new DatabaseTabHeader(id, Path.GetFileNameWithoutExtension(Program.Settings.PathDatabase = window.TbPathDatabase.Text)) + { + CloseTab = CloseTab, + iLock = { IsVisible = false }, + iUnlock = { IsVisible = true } + }; + + DatabaseControl db = new DatabaseControl + { + ViewModel = + { + Database = new Database { Folders = new List(), Logins = new List() }, + MasterPassword = window.TbPassword.Text, + Iterations = int.Parse(window.TbIteration.Text), + NumberOfEncryptionProcedures = int.Parse(window.TbNumberOfEncryptionProcedures.Text), + IsLockDatabase = false, + IsUnlockDatabase = true, + PathDatabase = window.TbPathDatabase.Text, + TabID = id, + UseCompression = window.CbUseCompression.IsChecked ?? false, + UseTrash = window.CbUseTrash.IsChecked ?? false + } + }; + + TabItems.Add(new TabItem { Header = tabHeader, Content = db }); + + SaveDatabase(db); + App.MainWindow.MessageStatusBar((string)Application.Current.FindResource("Not3") + $" {Path.GetFileNameWithoutExtension(Program.Settings.PathDatabase)}"); + } + } + private void ShowSearchWindow() + { + if (SelectedTabItem == null || SelectedTabItem.ViewModel.IsLockDatabase) return; + App.SearchWindow = new SearchWindow(); + + for (int index = 0; index < SelectedTabItem.ViewModel.Database.Folders.Count; index++) + App.SearchWindow.SearchViewModel.AddFolder(SelectedTabItem.ViewModel.Database.Folders[index]); + + App.SearchWindow.ShowDialog(App.MainWindow); + } + private void SaveAllDatabases() + { + for (int index = 0; index < TabItems.Count; index++) + SaveDatabase((DatabaseControl)TabItems[index].Content); + } + private void OpenSettingsWindow() + { + _settingsWindow = new SettingsWindow(); + _settingsWindow.ShowDialog(App.MainWindow); + } + private void ChangeMasterPassword() + { + _windowChangeMasterPassword = new ChangeMasterPasswordWindow(); + _windowChangeMasterPassword.ShowDialog(App.MainWindow); + } + private void ClearGC() + { + for (int index = 0; index < TabItems.Count; index++) + { + DatabaseControl item = (DatabaseControl)TabItems[index].Content; + for (int i = 0; i < item.ViewModel.Router.NavigationStack.Count; i++) + item.ViewModel.Router.NavigationStack.Remove(item.ViewModel.Router.NavigationStack[i]); + } + GC.Collect(0, GCCollectionMode.Forced); + App.MainWindow.MessageStatusBar((string)Application.Current.FindResource("ClearGC")); + } + private void OpenTrashWindow() + { + if (IsUnlockDatabase) + { + TrashWindow = new TrashWindow(); + TrashWindow.ShowDialog(App.MainWindow); + } + } + + private void CheckUpdate() => App.CheckUpdate(true); + private void ExitApplication() => App.MainWindow.Close(); + private void SaveSettings() => SaveAndLoadSettings.SaveSettings(); + } } \ No newline at end of file diff --git a/OlibKey.csproj b/OlibKey.csproj index fc9cb94..10051b0 100644 --- a/OlibKey.csproj +++ b/OlibKey.csproj @@ -3,6 +3,8 @@ WinExe net5.0 AnyCPU;x64 + 3.2.0 + 3.2.0 @@ -13,10 +15,10 @@ false true app.ico - 3.1.1 + 3.2.0 Dmitry Zhutkov © Dmitry Zhutkov 2020 - OlibKey - an open source password manager. + OlibKey - cross-platform, modern, open source password manager. true LICENSE.md Publish @@ -45,9 +47,9 @@ - - - + + + @@ -62,4 +64,12 @@ + + + FolderListItem.axaml + + + TrashWindow.axaml + + \ No newline at end of file diff --git a/OlibKey.sln b/OlibKey.sln index afde55b..91713d5 100644 --- a/OlibKey.sln +++ b/OlibKey.sln @@ -25,6 +25,8 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E7112F2A-E8C2-4BD4-BA4F-413BCBC3C55A} EndGlobalSection diff --git a/Program.cs b/Program.cs index 5824e6b..00e4a8e 100644 --- a/Program.cs +++ b/Program.cs @@ -1,45 +1,77 @@ using Avalonia; using Avalonia.Controls; using Avalonia.ReactiveUI; +using OlibKey.Core; +using OlibKey.Structures; using OlibKey.ViewModels.Pages; using OlibKey.Views.Pages; using ReactiveUI; using Splat; using System; -using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Runtime.InteropServices; +using System.Security.Principal; +using System.Diagnostics; namespace OlibKey { - class Program - { - [STAThread] - public static void Main(string[] args) => BuildAvaloniaApp().Start(AppMain, args); - - public static AppBuilder BuildAvaloniaApp() => - AppBuilder.Configure() - .UsePlatformDetect() - .LogToDebug() - .UseReactiveUI() - .With(new Win32PlatformOptions { AllowEglInitialization = false, UseDeferredRendering = true }) - .With(new MacOSPlatformOptions { ShowInDock = true }) - .With(new AvaloniaNativePlatformOptions { UseGpu = true, UseDeferredRendering = true }) - .With(new X11PlatformOptions { UseGpu = true, UseEGL = true }); - - private static void AppMain(Application app, string[] args) - { - List files = args.ToList(); - - App.MainWindowViewModel = new MainWindowViewModel { OpenStorages = files }; - - Locator.CurrentMutable.Register>(() => new CreateLoginPage()); - Locator.CurrentMutable.Register>(() => new StartPage()); - Locator.CurrentMutable.Register>(() => new LoginInformationPage()); - Locator.CurrentMutable.Register>(() => new EditLoginPage()); - - App.MainWindow = new MainWindow { DataContext = App.MainWindowViewModel }; - - app.Run(App.MainWindow); - } - } + public static class Program + { + public static Settings Settings { get; set; } + + [STAThread] + public static void Main(string[] args) + { + try + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && AppDomain.CurrentDomain.BaseDirectory.ToLower().Contains("program files") && !IsAdmin()) + { + Process.Start(new ProcessStartInfo + { + FileName = "OlibKey", + UseShellExecute = true, + Verb = "runas" + }); + return; + } + + Settings = File.Exists(AppDomain.CurrentDomain.BaseDirectory + "settings.xml") + ? SaveAndLoadSettings.LoadSettings() + : new Settings(); + + BuildAvaloniaApp().Start(AppMain, args); + } + catch (Exception ex) + { + Log.WriteFatal(ex); + } + } + + private static AppBuilder BuildAvaloniaApp() => + AppBuilder.Configure() + .UsePlatformDetect() + .LogToDebug() + .UseReactiveUI() + .With(new Win32PlatformOptions { AllowEglInitialization = Settings.UsingGPU, UseDeferredRendering = true }) + .With(new MacOSPlatformOptions { ShowInDock = true }) + .With(new AvaloniaNativePlatformOptions { UseGpu = Settings.UsingGPU, UseDeferredRendering = true }) + .With(new X11PlatformOptions { UseGpu = Settings.UsingGPU, UseEGL = true }); + + private static void AppMain(Application app, string[] args) + { + App.MainWindowViewModel = new MainWindowViewModel { OpenStorages = args.ToList() }; + + Locator.CurrentMutable.Register>(() => new CreateLoginPage()); + Locator.CurrentMutable.Register>(() => new StartPage()); + Locator.CurrentMutable.Register>(() => new LoginInformationPage()); + Locator.CurrentMutable.Register>(() => new EditLoginPage()); + + App.MainWindow = new MainWindow { DataContext = App.MainWindowViewModel }; + + app.Run(App.MainWindow); + } + + public static bool IsAdmin() => new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator); + } } diff --git a/README.md b/README.md index 2f57d15..dda0d24 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # OlibKey ![GitHub release (latest by date)](https://img.shields.io/github/v/release/MagnificentEagle/OlibPasswordManager) ![GitHub](https://img.shields.io/github/license/MagnificentEagle/OlibPasswordManager) [![CodeFactor](https://www.codefactor.io/repository/github/magnificenteagle/olibkey/badge)](https://www.codefactor.io/repository/github/magnificenteagle/olibkey) -![](https://github.com/MagnificentEagle/OlibPasswordManager/blob/master/ForRepository/ScreenProgram.png) +![](https://github.com/MagnificentEagle/OlibKey/blob/master/ForRepository/ScreenProgram.png) OlibKey is free software that allows you to store passwords, notes, documents and other important personal data on your computer. Powered by Microsoft .NET 5 Prewiev 7 using Avalonia UI. With OlibKey, you can store passwords on your computer **using AES encryption**. @@ -44,4 +44,4 @@ This version supports other platforms (x86, ARM), .NET Runtime is required to ru ## Where can I watch previews? You can watch the previews in the "dev-channel", where all the latest changes are posted. When the release is ready, a request is made to merge this branch into "master". -> **Attention:** these releases may be unstable and may even damage your base. Use only if you know what you are doing. It is recommended to make a backup copy of the database. +> **Attention:** these releases may be unstable and may even damage your base. Use only if you know what you are doing. It is recommended to make a backup copy of the database. \ No newline at end of file diff --git a/Structures/Database.cs b/Structures/Database.cs index 0882af1..1217ce3 100644 --- a/Structures/Database.cs +++ b/Structures/Database.cs @@ -10,6 +10,9 @@ public class Login public string Email { get; set; } public string TimeCreate { get; set; } public string TimeChanged { get; set; } + public string DeleteDate { get; set; } + + public bool Favorite { get; set; } public string FolderID { get; set; } @@ -58,6 +61,7 @@ public class Folder { public string Name { get; set; } public string ID { get; set; } + public string DeleteDate { get; set; } } public class CustomField { @@ -67,10 +71,16 @@ public class CustomField public string TextElement { get; set; } public bool CheckedElement { get; set; } } + public class Trash + { + public List Logins; + public List Folders; + } public class Database { public List Logins; public List Folders; + public Trash Trash; } } diff --git a/Structures/Settings.cs b/Structures/Settings.cs index d956c81..62ebe5d 100644 --- a/Structures/Settings.cs +++ b/Structures/Settings.cs @@ -10,6 +10,11 @@ public class Settings public int BlockDuration { get; set; } = 5; public bool AutoblockEnabled { get; set; } = true; public int MessageDuration { get; set; } = 3; + public bool UsingGPU { get; set; } = false; + public int DaysAfterDeletion { get; set; } = 10; + public bool AutoRemoveItemsTrash { get; set; } = true; + public bool ClearingTheClipboard { get; set; } + public int TimeToClearTheClipboard { get; set; } = 10; public string GenerationCount { get; set; } = "10"; public bool GeneratorAllowLowercase { get; set; } = true; diff --git a/ViewModels/Controls/DatabaseControlViewModel.cs b/ViewModels/Controls/DatabaseControlViewModel.cs index 933b06e..37febb0 100644 --- a/ViewModels/Controls/DatabaseControlViewModel.cs +++ b/ViewModels/Controls/DatabaseControlViewModel.cs @@ -20,6 +20,9 @@ public class DatabaseControlViewModel : ReactiveObject, IScreen public int Iterations { get; set; } public int NumberOfEncryptionProcedures { get; set; } + public bool UseCompression { get; set; } + public bool UseTrash { get; set; } = true; + private bool _isUnlockDatabase; private bool _isLockDatabase; @@ -29,13 +32,6 @@ public class DatabaseControlViewModel : ReactiveObject, IScreen private RoutingState _router = new RoutingState(); - #region ReactiveCommands - - private ReactiveCommand CreateLoginCommand { get; } - private ReactiveCommand ShowSearchWindowCommand { get; } - - #endregion - #region Propertie's public ObservableCollection LoginList @@ -70,15 +66,11 @@ public int SelectedIndex public string MasterPassword { get; set; } private LoginListItem SelectedLoginItem { get { try { return LoginList[SelectedIndex]; } catch { return null; } } } - #endregion + #endregion - public DatabaseControlViewModel() - { - CreateLoginCommand = ReactiveCommand.Create(CreateLogin); - ShowSearchWindowCommand = ReactiveCommand.Create(ShowSearchWindow); - SelectedIndex = -1; - } - public void SearchSelectLogin(LoginListItem i) + public DatabaseControlViewModel() => SelectedIndex = -1; + + public void SearchSelectLogin(LoginListItem i) { foreach (LoginListItem item in LoginList.Where(item => item.LoginID == i.LoginID)) { @@ -89,7 +81,8 @@ public void SearchSelectLogin(LoginListItem i) private void ShowSearchWindow() { App.SearchWindow = new SearchWindow(); - foreach (Folder folder in Database.Folders) App.SearchWindow.SearchViewModel.AddFolder(folder); + for (int index = 0; index < Database.Folders.Count; index++) App.SearchWindow.SearchViewModel.AddFolder(Database.Folders[index]); + App.SearchWindow.ShowDialog(App.MainWindow); } public void AddLogin(Login loginContent) @@ -107,7 +100,7 @@ public void AddLogin(Login loginContent) Router.Navigate.Execute(new StartPageViewModel(this)); } - public void CreateLogin() + private void CreateLogin() { SelectedIndex = -1; Router.Navigate.Execute(new CreateLoginPageViewModel(Database, this) @@ -152,22 +145,22 @@ public void ClearLoginsList() //// Problem with ListBox //// - //public void MoveUp() => MoveItem(-1); - - //public void MoveDown() => MoveItem(1); - - //private void MoveItem(int direction) - //{ - // if (SelectedLoginItem == null) - // return; - - // var newIndex = SelectedIndex + direction; - - // if (newIndex < 0 || newIndex >= LoginsList.Count) - // return; - - // LoginsList.Move(SelectedIndex, newIndex); - // SelectedIndex = newIndex; - //} + // public void MoveUp() => MoveItem(-1); + // + // public void MoveDown() => MoveItem(1); + // + // private void MoveItem(int direction) + // { + // if (SelectedLoginItem == null) + // return; + // + // var newIndex = SelectedIndex + direction; + // + // if (newIndex < 0 || newIndex >= LoginList.Count) + // return; + // + // LoginList.Move(SelectedIndex, newIndex); + // SelectedIndex = newIndex; + // } } } diff --git a/ViewModels/Pages/CreateLoginPageViewModel.cs b/ViewModels/Pages/CreateLoginPageViewModel.cs index 85d5da6..9476f44 100644 --- a/ViewModels/Pages/CreateLoginPageViewModel.cs +++ b/ViewModels/Pages/CreateLoginPageViewModel.cs @@ -8,103 +8,92 @@ using System.Collections.ObjectModel; using System.Globalization; using System.Linq; -using System.Reactive; namespace OlibKey.ViewModels.Pages { - public class CreateLoginPageViewModel : ReactiveObject, IRoutableViewModel - { - #region ReactiveCommands - public ReactiveCommand BackCommand { get; } - public ReactiveCommand CreateLoginCommand { get; } - public ReactiveCommand AddCustomFieldCommand { get; } - #endregion + public class CreateLoginPageViewModel : ReactiveObject, IRoutableViewModel + { + private int _selectionFolderIndex; + private ObservableCollection _customFields; - private int _selectionFolderIndex; - private ObservableCollection _CustomFields; + #region Property's - #region Property's - public int Type { get; set; } - public Login NewLogin { get; set; } - private int SelectionFolderIndex - { - get => _selectionFolderIndex; - set - { - this.RaiseAndSetIfChanged(ref _selectionFolderIndex, value); - NewLogin.FolderID = SelectionFolderItem.ID; - } - } - private Folder SelectionFolderItem { get { try { return Folders[SelectionFolderIndex]; } catch { return null; } } } - private ObservableCollection Folders { get; set; } - public ObservableCollection CustomFields - { - get => _CustomFields; - set => this.RaiseAndSetIfChanged(ref _CustomFields, value); - } + private int Type { get; set; } + private Login NewLogin { get; set; } + private int SelectionFolderIndex + { + get => _selectionFolderIndex; + set + { + this.RaiseAndSetIfChanged(ref _selectionFolderIndex, value); + NewLogin.FolderID = SelectionFolderItem.ID; + } + } + private Folder SelectionFolderItem { get { try { return Folders[SelectionFolderIndex]; } catch { return null; } } } + private ObservableCollection Folders { get; set; } - #endregion + private ObservableCollection CustomFields + { + get => _customFields; + set => this.RaiseAndSetIfChanged(ref _customFields, value); + } - public Action BackPageCallback { get; set; } - public Action CreateLoginCallback { get; set; } + #endregion - // routing - public string UrlPathSegment => "/addLogin"; - public IScreen HostScreen { get; } + public Action BackPageCallback { get; set; } + public Action CreateLoginCallback { get; set; } + // routing + public string UrlPathSegment => "/addLogin"; + public IScreen HostScreen { get; } - public CreateLoginPageViewModel(Database db, IScreen screen = null) - { - HostScreen = screen ?? Locator.Current.GetService(); + public CreateLoginPageViewModel(Database db, IScreen screen = null) + { + HostScreen = screen ?? Locator.Current.GetService(); - NewLogin = new Login - { - CustomFields = new System.Collections.Generic.List() - }; - CustomFields = new ObservableCollection(); + NewLogin = new Login + { + CustomFields = new System.Collections.Generic.List() + }; + CustomFields = new ObservableCollection(); - BackCommand = ReactiveCommand.Create(BackVoid); - CreateLoginCommand = ReactiveCommand.Create(CreateLogin); - AddCustomFieldCommand = ReactiveCommand.Create(AddCustomField); + Folders = new ObservableCollection + { + new Folder { ID = null, Name = (string)Application.Current.FindResource("NotChosen") } + }; - Folders = new ObservableCollection - { - new Folder { ID = null, Name = (string)Application.Current.FindResource("NotChosen") } - }; + if (db.Folders != null) foreach (Folder i in db.Folders) Folders.Add(i); - if (db.Folders != null) foreach (Folder i in db.Folders) Folders.Add(i); + SelectionFolderIndex = Type = 0; + } - SelectionFolderIndex = 0; - Type = 0; - } - - private void CreateLogin() - { - NewLogin.CustomFields.AddRange(CustomFields.Select(item => item.HousingElement.CustomField)); - NewLogin.TimeCreate = DateTime.Now.ToString(CultureInfo.CurrentCulture); - CreateLoginCallback?.Invoke(NewLogin); - App.MainWindow.MessageStatusBar((string)Application.Current.FindResource("Not1")); - } - private void AddCustomField() - { - CustomFields.Add(new CustomFieldListItem(new Housing - { - CustomField = new CustomField { Type = Type }, - IsEnabled = true - }) - { - ID = Guid.NewGuid().ToString("N"), - DeleteCustomField = DeleteCustomField - }); - } - private void DeleteCustomField(string id) - { - foreach (CustomFieldListItem item in CustomFields.Where(item => item.ID == id)) - { - _ = CustomFields.Remove(item); - break; - } - } - private void BackVoid() => BackPageCallback?.Invoke(); - } + private void CreateLogin() + { + NewLogin.CustomFields.AddRange(CustomFields.Select(item => item.HousingElement.CustomField)); + NewLogin.TimeCreate = DateTime.Now.ToString(CultureInfo.CurrentCulture); + CreateLoginCallback?.Invoke(NewLogin); + App.MainWindow.MessageStatusBar((string)Application.Current.FindResource("Not1")); + } + private void AddCustomField() + { + CustomFields.Add(new CustomFieldListItem(new Housing + { + CustomField = new CustomField { Type = Type }, + IsEnabled = true + }) + { + ID = Guid.NewGuid().ToString("N"), + DeleteCustomField = DeleteCustomField + }); + } + private void DeleteCustomField(string id) + { + foreach (CustomFieldListItem item in CustomFields.Where(item => item.ID == id)) + { + CustomFields.Remove(item); + break; + } + } + private void Back() => BackPageCallback?.Invoke(); + } } \ No newline at end of file diff --git a/ViewModels/Pages/EditLoginPageViewModel.cs b/ViewModels/Pages/EditLoginPageViewModel.cs index 16f394d..b373fec 100644 --- a/ViewModels/Pages/EditLoginPageViewModel.cs +++ b/ViewModels/Pages/EditLoginPageViewModel.cs @@ -6,220 +6,221 @@ using ReactiveUI; using Splat; using System; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.Globalization; using System.Linq; -using System.Reactive; namespace OlibKey.ViewModels.Pages { - public class EditLoginPageViewModel : ReactiveObject, IRoutableViewModel - { - private int _selectionFolderIndex; - - #region Section's - - private bool VisiblePasswordSection { get; set; } - private bool VisibleBankCardSection { get; set; } - private bool VisiblePersonalDataSection { get; set; } - private bool VisibleReminderSection { get; set; } - private bool VisibleDateChanged { get; set; } - - #endregion - - #region ReactiveCommand's - - private ReactiveCommand SaveLoginCommand { get; } - private ReactiveCommand DeleteLoginCommand { get; } - private ReactiveCommand CancelCommand { get; } - private ReactiveCommand AddCustomFieldCommand { get; } - - #endregion - - #region Property's - - public int Type { get; set; } - public ObservableCollection CustomFields { get; set; } - private int SelectionFolderIndex - { - get => _selectionFolderIndex; - set => this.RaiseAndSetIfChanged(ref _selectionFolderIndex, value); - } - - private Folder SelectionFolderItem { get { try { return Folders[SelectionFolderIndex]; } catch { return null; } } } - private ObservableCollection Folders { get; set; } - - public LoginListItem LoginList; - - #endregion - - public Action EditCompleteCallback; - public Action CancelCallback; - public Action DeleteLoginCallback; - - private Login NewLogin { get; set; } - - // routing - public string UrlPathSegment => "/editLogin"; - - public IScreen HostScreen { get; } - - public EditLoginPageViewModel(LoginListItem acc, Database db, IScreen screen = null) - { - HostScreen = screen ?? Locator.Current.GetService(); - - - CustomFields = new ObservableCollection(); - - LoginList = acc; - - NewLogin = new Login - { - Name = acc.LoginItem.Name, - Username = acc.LoginItem.Username, - Email = acc.LoginItem.Email, - Note = acc.LoginItem.Note, - Type = acc.LoginItem.Type, - TimeCreate = acc.LoginItem.TimeCreate - }; - - switch (acc.LoginItem.Type) - { - case 0: - VisiblePasswordSection = true; - VisibleBankCardSection = false; - VisiblePersonalDataSection = false; - VisibleReminderSection = false; - - NewLogin.Password = acc.LoginItem.Password; - NewLogin.WebSite = acc.LoginItem.WebSite; - break; - case 1: - VisiblePasswordSection = false; - VisibleBankCardSection = true; - VisiblePersonalDataSection = false; - VisibleReminderSection = false; - - NewLogin.TypeBankCard = acc.LoginItem.TypeBankCard; - NewLogin.DateCard = acc.LoginItem.DateCard; - NewLogin.SecurityCode = acc.LoginItem.SecurityCode; - break; - case 2: - VisiblePasswordSection = false; - VisibleBankCardSection = false; - VisiblePersonalDataSection = true; - VisibleReminderSection = false; - - NewLogin.Number = acc.LoginItem.Number; - NewLogin.PlaceOfIssue = acc.LoginItem.PlaceOfIssue; - NewLogin.SocialSecurityNumber = acc.LoginItem.SocialSecurityNumber; - NewLogin.TIN = acc.LoginItem.TIN; - NewLogin.Telephone = acc.LoginItem.Telephone; - NewLogin.Company = acc.LoginItem.Company; - NewLogin.Postcode = acc.LoginItem.Postcode; - NewLogin.Country = acc.LoginItem.Country; - NewLogin.Region = acc.LoginItem.Region; - NewLogin.City = acc.LoginItem.City; - NewLogin.Address = acc.LoginItem.Address; - break; - case 3: - VisiblePasswordSection = false; - VisibleBankCardSection = false; - VisiblePersonalDataSection = false; - VisibleReminderSection = true; - - NewLogin.IsReminderActive = acc.LoginItem.IsReminderActive; - break; - case 4: - VisiblePasswordSection = false; - VisibleBankCardSection = false; - VisiblePersonalDataSection = false; - VisibleReminderSection = false; - break; - } - - SaveLoginCommand = ReactiveCommand.Create(SaveLogin); - CancelCommand = ReactiveCommand.Create(BackVoid); - DeleteLoginCommand = ReactiveCommand.Create(DeleteLogin); - AddCustomFieldCommand = ReactiveCommand.Create(AddCustomField); - - Folders = new ObservableCollection - { - new Folder { ID = null, Name = (string)Application.Current.FindResource("NotChosen") } - }; - - if (db.Folders != null) foreach (Folder i in db.Folders) Folders.Add(i); - - SelectionFolderIndex = 0; - foreach (Folder i in Folders.Where(i => i.ID == LoginList.LoginItem.FolderID)) - { - SelectionFolderIndex = Folders.IndexOf(i); - break; - } - - foreach (CustomField i in acc.LoginItem.CustomFields) - { - CustomFields.Add(new CustomFieldListItem(new Housing - { - CustomField = i, - IsEnabled = true - }) - { - ID = Guid.NewGuid().ToString("N"), - DeleteCustomField = DeleteCustomField - }); - } - } - - private void SaveLogin() - { - LoginList.LoginItem = NewLogin; - LoginList.LoginItem.FolderID = SelectionFolderItem.ID; - - LoginList.LoginItem.CustomFields = CustomFields.Select(item => item.HousingElement.CustomField).ToList(); - LoginList.LoginItem.TimeChanged = DateTime.Now.ToString(CultureInfo.CurrentCulture); - if (NewLogin.IsReminderActive) - { - LoginList.ReminderTimer.Interval = new TimeSpan(0, 0, 3); - LoginList.ReminderTimer.Start(); - } - else - { - LoginList.ReminderTimer?.Stop(); - } - LoginList.EditedLogin(); - - EditCompleteCallback?.Invoke(LoginList); - App.MainWindow.MessageStatusBar((string)Application.Current.FindResource("Not2")); - } - private async void DeleteLogin() - { - MessageBox.MessageBoxResult r = await MessageBox.Show(App.MainWindow, null, - (string)Application.Current.FindResource("MB2"), (string)Application.Current.FindResource("Message"), - MessageBox.MessageBoxButtons.YesNo, MessageBox.MessageBoxIcon.Question); - if (r == MessageBox.MessageBoxResult.Yes) - DeleteLoginCallback?.Invoke(); - } - private void AddCustomField() - { - CustomFields.Add(new CustomFieldListItem(new Housing - { - CustomField = new CustomField { Type = Type }, - IsEnabled = true - }) - { - ID = Guid.NewGuid().ToString("N"), - DeleteCustomField = DeleteCustomField - }); - } - private void DeleteCustomField(string id) - { - foreach (CustomFieldListItem item in CustomFields.Where(item => item.ID == id)) - { - CustomFields.Remove(item); - break; - } - } - private void BackVoid() => CancelCallback?.Invoke(LoginList); - } + public class EditLoginPageViewModel : ReactiveObject, IRoutableViewModel + { + private int _selectionFolderIndex; + + #region Section's + + private bool VisiblePasswordSection { get; set; } + private bool VisibleBankCardSection { get; set; } + private bool VisiblePersonalDataSection { get; set; } + private bool VisibleReminderSection { get; set; } + private bool VisibleDateChanged { get; set; } + + #endregion + + #region Property's + + private int Type { get; set; } + private ObservableCollection CustomFields { get; set; } + private int SelectionFolderIndex + { + get => _selectionFolderIndex; + set => this.RaiseAndSetIfChanged(ref _selectionFolderIndex, value); + } + + private Folder SelectionFolderItem { get { try { return Folders[SelectionFolderIndex]; } catch { return null; } } } + private ObservableCollection Folders { get; set; } + + private LoginListItem LoginList; + + #endregion + + public Action EditCompleteCallback; + public Action CancelCallback; + public Action DeleteLoginCallback; + + private Login NewLogin { get; set; } + + // routing + public string UrlPathSegment => "/editLogin"; + + public IScreen HostScreen { get; } + + public EditLoginPageViewModel(LoginListItem acc, Database db, IScreen screen = null) + { + HostScreen = screen ?? Locator.Current.GetService(); + + CustomFields = new ObservableCollection(); + + LoginList = acc; + + NewLogin = new Login + { + Name = acc.LoginItem.Name, + Username = acc.LoginItem.Username, + Email = acc.LoginItem.Email, + Note = acc.LoginItem.Note, + Type = acc.LoginItem.Type, + TimeCreate = acc.LoginItem.TimeCreate + }; + + switch (acc.LoginItem.Type) + { + case 0: + VisiblePasswordSection = true; + VisibleBankCardSection = false; + VisiblePersonalDataSection = false; + VisibleReminderSection = false; + + NewLogin.Password = acc.LoginItem.Password; + NewLogin.WebSite = acc.LoginItem.WebSite; + break; + case 1: + VisiblePasswordSection = false; + VisibleBankCardSection = true; + VisiblePersonalDataSection = false; + VisibleReminderSection = false; + + NewLogin.TypeBankCard = acc.LoginItem.TypeBankCard; + NewLogin.DateCard = acc.LoginItem.DateCard; + NewLogin.SecurityCode = acc.LoginItem.SecurityCode; + break; + case 2: + VisiblePasswordSection = false; + VisibleBankCardSection = false; + VisiblePersonalDataSection = true; + VisibleReminderSection = false; + + NewLogin.Number = acc.LoginItem.Number; + NewLogin.PlaceOfIssue = acc.LoginItem.PlaceOfIssue; + NewLogin.SocialSecurityNumber = acc.LoginItem.SocialSecurityNumber; + NewLogin.TIN = acc.LoginItem.TIN; + NewLogin.Telephone = acc.LoginItem.Telephone; + NewLogin.Company = acc.LoginItem.Company; + NewLogin.Postcode = acc.LoginItem.Postcode; + NewLogin.Country = acc.LoginItem.Country; + NewLogin.Region = acc.LoginItem.Region; + NewLogin.City = acc.LoginItem.City; + NewLogin.Address = acc.LoginItem.Address; + break; + case 3: + VisiblePasswordSection = false; + VisibleBankCardSection = false; + VisiblePersonalDataSection = false; + VisibleReminderSection = true; + + NewLogin.IsReminderActive = acc.LoginItem.IsReminderActive; + break; + case 4: + VisiblePasswordSection = false; + VisibleBankCardSection = false; + VisiblePersonalDataSection = false; + VisibleReminderSection = false; + break; + } + + Folders = new ObservableCollection + { + new Folder { ID = null, Name = (string)Application.Current.FindResource("NotChosen") } + }; + + if (db.Folders != null) foreach (Folder i in db.Folders) Folders.Add(i); + + SelectionFolderIndex = 0; + foreach (Folder i in Folders.Where(i => i.ID == LoginList.LoginItem.FolderID)) + { + SelectionFolderIndex = Folders.IndexOf(i); + break; + } + + for (int i = 0; i < acc.LoginItem.CustomFields.Count; i++) + { + CustomFields.Add(new CustomFieldListItem(new Housing + { + CustomField = acc.LoginItem.CustomFields[i], + IsEnabled = true + }) + { + ID = Guid.NewGuid().ToString("N"), + DeleteCustomField = DeleteCustomField + }); + } + } + + private void SaveLogin() + { + LoginList.LoginItem = NewLogin; + LoginList.LoginItem.FolderID = SelectionFolderItem.ID; + + LoginList.LoginItem.CustomFields = CustomFields.Select(item => item.HousingElement.CustomField).ToList(); + LoginList.LoginItem.TimeChanged = DateTime.Now.ToString(CultureInfo.CurrentCulture); + + if (NewLogin.IsReminderActive) + { + LoginList.ReminderTimer.Interval = new TimeSpan(0, 0, 1); + LoginList.ReminderTimer.Start(); + } + else + LoginList.ReminderTimer?.Stop(); + + LoginList.EditedLogin(); + + EditCompleteCallback?.Invoke(LoginList); + App.MainWindow.MessageStatusBar((string)Application.Current.FindResource("Not2")); + } + private async void DeleteLogin() + { + if (App.MainWindowViewModel.SelectedTabItem.ViewModel.UseTrash) + { + if (App.MainWindowViewModel.SelectedTabItem.ViewModel.Database.Trash == null) + { + App.MainWindowViewModel.SelectedTabItem.ViewModel.Database.Trash = new Trash + { + Logins = new List(), + Folders = new List() + }; + } + LoginList.LoginItem.DeleteDate = DateTime.Now.ToString(System.Threading.Thread.CurrentThread.CurrentUICulture); + App.MainWindowViewModel.SelectedTabItem.ViewModel.Database.Trash.Logins.Add(LoginList.LoginItem); + DeleteLoginCallback?.Invoke(); + } + else + { + if (await MessageBox.Show(App.MainWindow, null, + (string)Application.Current.FindResource("MB2"), (string)Application.Current.FindResource("Message"), + MessageBox.MessageBoxButtons.YesNo, MessageBox.MessageBoxIcon.Question) == MessageBox.MessageBoxResult.Yes) + DeleteLoginCallback?.Invoke(); + } + } + private void AddCustomField() + { + CustomFields.Add(new CustomFieldListItem(new Housing + { + CustomField = new CustomField { Type = Type }, + IsEnabled = true + }) + { + ID = Guid.NewGuid().ToString("N"), + DeleteCustomField = DeleteCustomField + }); + } + private void DeleteCustomField(string id) + { + foreach (CustomFieldListItem item in CustomFields.Where(item => item.ID == id)) + { + CustomFields.Remove(item); + break; + } + } + private void Back() => CancelCallback?.Invoke(LoginList); + } } \ No newline at end of file diff --git a/ViewModels/Pages/LoginInformationPageViewModel.cs b/ViewModels/Pages/LoginInformationPageViewModel.cs index db0cee9..3d6863a 100644 --- a/ViewModels/Pages/LoginInformationPageViewModel.cs +++ b/ViewModels/Pages/LoginInformationPageViewModel.cs @@ -15,7 +15,7 @@ namespace OlibKey.ViewModels.Pages public class LoginInformationPageViewModel : ReactiveObject, IRoutableViewModel { private int _selectionFolderIndex; - private ObservableCollection _CustomFields; + private ObservableCollection _customFields; #region Section's @@ -28,26 +28,8 @@ public class LoginInformationPageViewModel : ReactiveObject, IRoutableViewModel #region ReactiveCommand's - public ReactiveCommand EditContentCommand { get; } - public ReactiveCommand CopyUsernameCommand { get; } - public ReactiveCommand CopyPasswordCommand { get; } - public ReactiveCommand CopyWebSiteCommand { get; } - public ReactiveCommand CopyTypeBankCommand { get; } - public ReactiveCommand CopyDateCardCommand { get; } - public ReactiveCommand CopySecurityCodeCommand { get; } - public ReactiveCommand CopyNumberCommand { get; } - public ReactiveCommand CopyPlaceOfIssueCommand { get; } - public ReactiveCommand OpenWebSiteCommand { get; } - public ReactiveCommand CopySocialSecurityNumberCommand { get; } - public ReactiveCommand CopyTINCommand { get; } - public ReactiveCommand CopyTelephoneCommand { get; } - public ReactiveCommand CopyCompanyCommand { get; } - public ReactiveCommand CopyPostcodeCommand { get; } - public ReactiveCommand CopyCountryCommand { get; } - public ReactiveCommand CopyRegionCommand { get; } - public ReactiveCommand CopyCityCommand { get; } - public ReactiveCommand CopyAddressCommand { get; } - public ReactiveCommand CopyEmailCommand { get; } + private ReactiveCommand EditContentCommand { get; } + private ReactiveCommand OpenWebSiteCommand { get; } #endregion @@ -59,14 +41,14 @@ private int SelectionFolderIndex } private ObservableCollection CustomFields { - get => _CustomFields; - set => this.RaiseAndSetIfChanged(ref _CustomFields, value); + get => _customFields; + set => this.RaiseAndSetIfChanged(ref _customFields, value); } private LoginListItem LoginItem { get; set; } private bool VisibleDateChanged { get; set; } private bool IsVisible { get; set; } = true; private ObservableCollection Folders { get; set; } - public Login LoginInformation { get; set; } + private Login LoginInformation { get; set; } #endregion @@ -84,9 +66,9 @@ public LoginInformationPageViewModel(LoginListItem acc, Database db, IScreen scr LoginItem = acc; CustomFields = new ObservableCollection(); - switch (LoginInformation.Type) + switch (LoginInformation.Type) { - case 0: + case 0: VisiblePasswordSection = true; VisibleBankCardSection = false; VisiblePersonalDataSection = false; @@ -122,25 +104,6 @@ public LoginInformationPageViewModel(LoginListItem acc, Database db, IScreen scr EditContentCommand = ReactiveCommand.Create(() => EditContentCallback?.Invoke(LoginItem)); - CopyUsernameCommand = ReactiveCommand.Create(() => { Application.Current.Clipboard.SetTextAsync(LoginInformation.Username); }); - CopyPasswordCommand = ReactiveCommand.Create(() => { Application.Current.Clipboard.SetTextAsync(LoginInformation.Password); }); - CopyWebSiteCommand = ReactiveCommand.Create(() => { Application.Current.Clipboard.SetTextAsync(LoginInformation.WebSite); }); - CopyTypeBankCommand = ReactiveCommand.Create(() => { Application.Current.Clipboard.SetTextAsync(LoginInformation.TypeBankCard); }); - CopyDateCardCommand = ReactiveCommand.Create(() => { Application.Current.Clipboard.SetTextAsync(LoginInformation.DateCard); }); - CopySecurityCodeCommand = ReactiveCommand.Create(() => { Application.Current.Clipboard.SetTextAsync(LoginInformation.SecurityCode); }); - CopyNumberCommand = ReactiveCommand.Create(() => { Application.Current.Clipboard.SetTextAsync(LoginInformation.Number); }); - CopyPlaceOfIssueCommand = ReactiveCommand.Create(() => { Application.Current.Clipboard.SetTextAsync(LoginInformation.PlaceOfIssue); }); - CopySocialSecurityNumberCommand = ReactiveCommand.Create(() => { Application.Current.Clipboard.SetTextAsync(LoginInformation.SocialSecurityNumber); }); - CopyTINCommand = ReactiveCommand.Create(() => { Application.Current.Clipboard.SetTextAsync(LoginInformation.TIN); }); - CopyTelephoneCommand = ReactiveCommand.Create(() => { Application.Current.Clipboard.SetTextAsync(LoginInformation.Telephone); }); - CopyCompanyCommand = ReactiveCommand.Create(() => { Application.Current.Clipboard.SetTextAsync(LoginInformation.Company); }); - CopyPostcodeCommand = ReactiveCommand.Create(() => { Application.Current.Clipboard.SetTextAsync(LoginInformation.Postcode); }); - CopyCountryCommand = ReactiveCommand.Create(() => { Application.Current.Clipboard.SetTextAsync(LoginInformation.Country); }); - CopyRegionCommand = ReactiveCommand.Create(() => { Application.Current.Clipboard.SetTextAsync(LoginInformation.Region); }); - CopyCityCommand = ReactiveCommand.Create(() => { Application.Current.Clipboard.SetTextAsync(LoginInformation.City); }); - CopyAddressCommand = ReactiveCommand.Create(() => { Application.Current.Clipboard.SetTextAsync(LoginInformation.Address); }); - CopyEmailCommand = ReactiveCommand.Create(() => { Application.Current.Clipboard.SetTextAsync(LoginInformation.Email); }); - OpenWebSiteCommand = ReactiveCommand.Create(() => { ProcessStartInfo psi = new ProcessStartInfo @@ -165,16 +128,25 @@ public LoginInformationPageViewModel(LoginListItem acc, Database db, IScreen scr break; } - foreach (CustomField i in LoginInformation.CustomFields) + for (int index = 0; index < LoginInformation.CustomFields.Count; index++) CustomFields.Add(new CustomFieldListItem(new Housing - { - CustomField = i, - IsEnabled = false - })); + {CustomField = LoginInformation.CustomFields[index], IsEnabled = false})); if (CustomFields.Count != 0) CustomFields[^1].SLine.IsVisible = false; if (CustomFields.Count == 0) IsVisible = false; } + + private void CopyInformation(string s) + { + Application.Current.Clipboard.SetTextAsync(s); + if (Program.Settings.ClearingTheClipboard) + { + App.ClearingClipboard.Stop(); + App.ClearingClipboard.Interval = new TimeSpan(0, 0, Program.Settings.TimeToClearTheClipboard); + App.ClearingClipboard.Start(); + } + App.MainWindow.MessageStatusBar((string)Application.Current.FindResource("Copied")); + } } } diff --git a/ViewModels/Windows/CheckingWeakPasswordsWindowViewModel.cs b/ViewModels/Windows/CheckingWeakPasswordsWindowViewModel.cs new file mode 100644 index 0000000..27cedda --- /dev/null +++ b/ViewModels/Windows/CheckingWeakPasswordsWindowViewModel.cs @@ -0,0 +1,106 @@ +using System.Collections.ObjectModel; +using System.Linq; +using System.Reactive; +using Avalonia; +using Avalonia.Controls; +using OlibKey.Core; +using OlibKey.Structures; +using OlibKey.Views.Controls; +using OlibKey.Views.Windows; +using ReactiveUI; + +namespace OlibKey.ViewModels.Windows +{ + public class CheckingWeakPasswordsWindowViewModel : ReactiveObject + { + private ObservableCollection _loginList = new ObservableCollection(); + + private double _overallComplexity; + + #region ReactiveCommand's + + private ReactiveCommand CloseWindowCommand { get; } + + #endregion + + #region Property's + + private ObservableCollection LoginList + { + get => _loginList; set => this.RaiseAndSetIfChanged(ref _loginList, value); + } + private double OverallComplexity + { + get => _overallComplexity; + set => this.RaiseAndSetIfChanged(ref _overallComplexity, value); + } + + #endregion + + public CheckingWeakPasswordsWindowViewModel() + { + CloseWindowCommand = ReactiveCommand.Create(() => { App.MainWindowViewModel.CheckingWindow.Close(); }); + + for (int index = 0; index < App.MainWindowViewModel.SelectedTabItem.ViewModel.LoginList.Count; index++) + { + LoginListItem item = App.MainWindowViewModel.SelectedTabItem.ViewModel.LoginList[index]; + if (item.LoginItem.Type == 0) + if (PasswordUtils.CheckPasswordStrength(item.LoginItem.Password) < 200) + Add(item.LoginItem, item.IconLogin, item.LoginID); + } + + double sum = 0; + + sum += App.MainWindowViewModel.SelectedTabItem.ViewModel.LoginList.Where(item => item.LoginItem.Type == 0) + .Aggregate(0, (current, item) => current + (PasswordUtils.CheckPasswordStrength(item.LoginItem.Password) > 300 + ? 300 + : PasswordUtils.CheckPasswordStrength(item.LoginItem.Password))); + + int count = App.MainWindowViewModel.SelectedTabItem.ViewModel.LoginList.Count(item => item.LoginItem.Type == 0); + + OverallComplexity = count == 0 ? 0 : sum / count; + } + + private void Add(Login a, Image i, string id) => + LoginList.Add(new LoginListItem(a) + { + LoginID = id, + IconLogin = { Source = i.Source }, + SelectedItem = { IsVisible = true }, + IsFavorite = { IsVisible = false } + }); + + private void SelectAll() + { + for (int index = 0; index < LoginList.Count; index++) LoginList[index].SelectedItem.IsChecked = true; + } + + private async void ChangeWeakPassword() + { + try + { + for (int index = 0; index < LoginList.Count; index++) + { + LoginListItem i = LoginList[index]; + if (i.SelectedItem.IsChecked ?? false) + { + foreach (LoginListItem item in App.MainWindowViewModel.SelectedTabItem.ViewModel.LoginList.Where( + item => item.LoginID == i.LoginID)) + { + item.LoginItem.Password = PasswordGenerator.RandomPassword(); + break; + } + } + } + await MessageBox.Show(App.MainWindowViewModel.CheckingWindow, null, (string)Application.Current.FindResource("Successfully"), (string)Application.Current.FindResource("Message"), + MessageBox.MessageBoxButtons.Ok, MessageBox.MessageBoxIcon.Information); + App.MainWindowViewModel.CheckingWindow.Close(); + } + catch + { + await MessageBox.Show(App.MainWindowViewModel.CheckingWindow, null, (string)Application.Current.FindResource("MB7"), (string)Application.Current.FindResource("Error"), + MessageBox.MessageBoxButtons.Ok, MessageBox.MessageBoxIcon.Error); + } + } + } +} diff --git a/ViewModels/Windows/SearchWindowViewModel.cs b/ViewModels/Windows/SearchWindowViewModel.cs index 9bf9e05..2ccb3e5 100644 --- a/ViewModels/Windows/SearchWindowViewModel.cs +++ b/ViewModels/Windows/SearchWindowViewModel.cs @@ -2,95 +2,104 @@ using OlibKey.Views.Controls; using ReactiveUI; using System; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.Reactive; namespace OlibKey.ViewModels.Windows { - public class SearchWindowViewModel : ReactiveObject - { - private ObservableCollection _loginList = new ObservableCollection(); - private ObservableCollection _folderList = new ObservableCollection(); + public class SearchWindowViewModel : ReactiveObject + { + private ObservableCollection _loginList = new ObservableCollection(); + private ObservableCollection _folderList = new ObservableCollection(); - private string _searchText; + private FolderListItem _selectedFolderItem; - private int _selectedLoginIndex; - private int _selectedFolderIndex; + private string _searchText; - #region ReactiveCommand's + private int _selectedLoginIndex; + private int _selectedFolderIndex; - public ReactiveCommand CreateFolderCommand { get; } - public ReactiveCommand DeleteFolderCommand { get; } - public ReactiveCommand EditFolderCommand { get; } - public ReactiveCommand UnselectFolderItemCommand { get; } + #region ReactiveCommand's - #endregion + private ReactiveCommand CreateFolderCommand { get; } + private ReactiveCommand DeleteFolderCommand { get; } + private ReactiveCommand EditFolderCommand { get; } + private ReactiveCommand UnselectFolderItemCommand { get; } - #region Property's + #endregion - private ObservableCollection LoginList - { - get => _loginList; set => this.RaiseAndSetIfChanged(ref _loginList, value); - } - public ObservableCollection FolderList - { - get => _folderList; set => this.RaiseAndSetIfChanged(ref _folderList, value); - } - public int SelectedFolderIndex - { - get => _selectedFolderIndex; set => this.RaiseAndSetIfChanged(ref _selectedFolderIndex, value); - } - private int SelectedLoginIndex - { - get => _selectedLoginIndex; - set - { - this.RaiseAndSetIfChanged(ref _selectedLoginIndex, value); - if (SelectedLoginIndex == -1) return; - App.MainWindowViewModel.SelectedTabItem.ViewModel.SearchSelectLogin(SelectedLoginItem); - App.SearchWindow.Close(); - } - } - public string SearchText - { - get => _searchText; set => this.RaiseAndSetIfChanged(ref _searchText, value); - } + #region Property's - #endregion + public ObservableCollection LoginList + { + get => _loginList; set => this.RaiseAndSetIfChanged(ref _loginList, value); + } + public ObservableCollection FolderList + { + get => _folderList; set => this.RaiseAndSetIfChanged(ref _folderList, value); + } + public int SelectedFolderIndex + { + get => _selectedFolderIndex; set => this.RaiseAndSetIfChanged(ref _selectedFolderIndex, value); + } + private int SelectedLoginIndex + { + get => _selectedLoginIndex; + set + { + this.RaiseAndSetIfChanged(ref _selectedLoginIndex, value); + if (SelectedLoginIndex == -1) return; + App.MainWindowViewModel.SelectedTabItem.ViewModel.SearchSelectLogin(SelectedLoginItem); + App.SearchWindow.Close(); + } + } + public string SearchText + { + get => _searchText; set => this.RaiseAndSetIfChanged(ref _searchText, value); + } - public SearchWindowViewModel() - { - CreateFolderCommand = ReactiveCommand.Create(CreateFolder); - DeleteFolderCommand = ReactiveCommand.Create(() => { FolderList.Remove(SelectedFolderItem); }); - EditFolderCommand = ReactiveCommand.Create(() => SelectedFolderItem.Focusing()); - UnselectFolderItemCommand = ReactiveCommand.Create(() => { SelectedFolderIndex = -1; }); + #endregion - SelectedLoginIndex = -1; - SelectedFolderIndex = -1; - } - public void AddLogin(LoginListItem Login) => LoginList.Add(Login); + public SearchWindowViewModel() + { + CreateFolderCommand = ReactiveCommand.Create(CreateFolder); + DeleteFolderCommand = ReactiveCommand.Create(() => + { + if (App.MainWindowViewModel.SelectedTabItem.ViewModel.UseTrash) + { + if (App.MainWindowViewModel.SelectedTabItem.ViewModel.Database.Trash == null) + { + App.MainWindowViewModel.SelectedTabItem.ViewModel.Database.Trash = new Trash + { + Logins = new List(), + Folders = new List() + }; + } + SelectedFolderItem.FolderContext.DeleteDate = DateTime.Now.ToString(System.Threading.Thread.CurrentThread.CurrentUICulture); + App.MainWindowViewModel.SelectedTabItem.ViewModel.Database.Trash.Folders.Add(SelectedFolderItem.FolderContext); + } + FolderList.Remove(SelectedFolderItem); + }); + EditFolderCommand = ReactiveCommand.Create(() => SelectedFolderItem.Focusing()); + UnselectFolderItemCommand = ReactiveCommand.Create(() => { SelectedFolderIndex = -1; }); - public void ClearLoginsList() => LoginList.Clear(); - public FolderListItem SelectedFolderItem { get { try { return FolderList[SelectedFolderIndex]; } catch { return null; } } } - public LoginListItem SelectedLoginItem { get { try { return LoginList[SelectedLoginIndex]; } catch { return null; } } } - private void CreateFolder() - { - FolderListItem a = new FolderListItem - { - DataContext = new Folder() - }; - a.FolderContext.ID = Guid.NewGuid().ToString("N"); - FolderList.Add(a); - } - public void AddFolder(Folder LoginContent) - { - FolderListItem ali = new FolderListItem - { - DataContext = LoginContent, - }; - ali._tbName.IsVisible = false; + SelectedLoginIndex = SelectedFolderIndex = -1; + } - FolderList.Add(ali); - } - } + public FolderListItem SelectedFolderItem + { + get => _selectedFolderItem; + set => this.RaiseAndSetIfChanged(ref _selectedFolderItem, value); + } + + private LoginListItem SelectedLoginItem { get { try { return LoginList[SelectedLoginIndex]; } catch { return null; } } } + private void CreateFolder() => + FolderList.Add(new FolderListItem + { + DataContext = new Folder(), + FolderContext = { ID = Guid.NewGuid().ToString("N") } + }); + public void AddFolder(Folder loginContent) => FolderList.Add(new FolderListItem { DataContext = loginContent, _tbName = { IsVisible = false } }); + } } diff --git a/ViewModels/Windows/TrashWindowViewModel.cs b/ViewModels/Windows/TrashWindowViewModel.cs new file mode 100644 index 0000000..8f09599 --- /dev/null +++ b/ViewModels/Windows/TrashWindowViewModel.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reactive; +using Avalonia; +using Avalonia.Controls; +using OlibKey.Structures; +using OlibKey.Views.Controls; +using OlibKey.Views.Windows; +using ReactiveUI; + +namespace OlibKey.ViewModels.Windows +{ + public class TrashWindowViewModel : ReactiveObject + { + private ObservableCollection _loginsList = new ObservableCollection(); + private ObservableCollection _foldersList = new ObservableCollection(); + + #region Property's + + private ObservableCollection LoginsList + { + get => _loginsList; + set => this.RaiseAndSetIfChanged(ref _loginsList, value); + } + private ObservableCollection FoldersList + { + get => _foldersList; + set => this.RaiseAndSetIfChanged(ref _foldersList, value); + } + + #endregion + + #region ReactiveCommand's + + private ReactiveCommand CloseCommand { get; } + + #endregion + + public TrashWindowViewModel() + { + CloseCommand = ReactiveCommand.Create(() => { App.MainWindowViewModel.TrashWindow.Close(); }); + + if (App.MainWindowViewModel.SelectedTabItem.ViewModel.Database.Trash == null) + App.MainWindowViewModel.SelectedTabItem.ViewModel.Database.Trash = new Trash + { + Folders = new List(), + Logins = new List() + }; + + for (int i = 0; i < App.MainWindowViewModel.SelectedTabItem.ViewModel.Database.Trash.Logins.Count; i++) + AddLogin(App.MainWindowViewModel.SelectedTabItem.ViewModel.Database.Trash.Logins[i]); + for (int i = 0; i < App.MainWindowViewModel.SelectedTabItem.ViewModel.Database.Trash.Folders.Count; i++) + AddFolder(App.MainWindowViewModel.SelectedTabItem.ViewModel.Database.Trash.Folders[i]); + } + + private async void ClearTrash() + { + if (await MessageBox.Show(App.MainWindow, null, + (string)Application.Current.FindResource("MB9"), (string)Application.Current.FindResource("Message"), + MessageBox.MessageBoxButtons.YesNo, MessageBox.MessageBoxIcon.Question) == MessageBox.MessageBoxResult.Yes) + { + App.MainWindowViewModel.SelectedTabItem.ViewModel.Database.Trash.Logins.Clear(); + App.MainWindowViewModel.SelectedTabItem.ViewModel.Database.Trash.Folders.Clear(); + LoginsList.Clear(); + FoldersList.Clear(); + } + } + private void RemoveSelectedItems() + { + for (int x = LoginsList.Count - 1; x > -1; x--) + if (LoginsList[x].SelectedItem.IsChecked ?? false) LoginsList.Remove(LoginsList[x]); + for (int x = FoldersList.Count - 1; x > -1; x--) + if (FoldersList[x].SelectedItem.IsChecked ?? false) FoldersList.Remove(FoldersList[x]); + + App.MainWindowViewModel.SelectedTabItem.ViewModel.Database.Trash.Logins = LoginsList.Select(item => item.LoginItem).ToList(); + App.MainWindowViewModel.SelectedTabItem.ViewModel.Database.Trash.Folders = FoldersList.Select(item => item.FolderContext).ToList(); + } + private void RestoreSelectedItems() + { + for (int x = LoginsList.Count - 1; x > -1; x--) + if (LoginsList[x].SelectedItem.IsChecked ?? false) + { + LoginsList[x].LoginItem.DeleteDate = null; + App.MainWindowViewModel.SelectedTabItem.ViewModel.LoginList.Add(new LoginListItem(LoginsList[x].LoginItem) + { + LoginID = Guid.NewGuid().ToString("N"), + IconLogin = { Source = LoginsList[x].IconLogin.Source }, + }); + LoginsList.Remove(LoginsList[x]); + } + for (int x = FoldersList.Count - 1; x > -1; x--) + if (FoldersList[x].SelectedItem.IsChecked ?? false) + { + FoldersList[x].FolderContext.DeleteDate = null; + App.MainWindowViewModel.SelectedTabItem.ViewModel.Database.Folders.Add(FoldersList[x].FolderContext); + FoldersList.Remove(FoldersList[x]); + } + + App.MainWindowViewModel.SelectedTabItem.ViewModel.Database.Trash.Logins = LoginsList.Select(item => item.LoginItem).ToList(); + App.MainWindowViewModel.SelectedTabItem.ViewModel.Database.Trash.Folders = FoldersList.Select(item => item.FolderContext).ToList(); + } + + private void AddLogin(Login a) + { + LoginListItem login = new LoginListItem(a) + { + SelectedItem = { IsVisible = true }, + IsFavorite = { IsEnabled = false } + }; + LoginsList.Add(login); + login.GetIconElement(); + } + private void AddFolder(Folder a) => + FoldersList.Add(new FolderListItem(a) + { + _tbName = { IsVisible = false }, + SelectedItem = { IsVisible = true } + }); + } +} diff --git a/Views/Controls/CustomElementListItem.axaml.cs b/Views/Controls/CustomElementListItem.axaml.cs index 06d3b73..3f9ad77 100644 --- a/Views/Controls/CustomElementListItem.axaml.cs +++ b/Views/Controls/CustomElementListItem.axaml.cs @@ -51,12 +51,8 @@ public CustomFieldListItem(Housing element) private void Delete(object sender, RoutedEventArgs e) => DeleteCustomField?.Invoke(ID); - private void CheckedPassword(object sender, RoutedEventArgs e) - { - CheckBox cb = (CheckBox)sender; - _tbPassword.PasswordChar = cb.IsChecked == true ? '\0' : '•'; - } - } + private void CheckedPassword(object sender, RoutedEventArgs e) => _tbPassword.PasswordChar = ((CheckBox)sender).IsChecked ?? false ? '\0' : '•'; + } public class Housing { public CustomField CustomField { get; set; } diff --git a/Views/Controls/DatabaseControl.axaml b/Views/Controls/DatabaseControl.axaml index 1f31f58..23a2712 100644 --- a/Views/Controls/DatabaseControl.axaml +++ b/Views/Controls/DatabaseControl.axaml @@ -14,12 +14,13 @@ - + + - diff --git a/Views/Controls/CustomFolderListItem.axaml b/Views/Controls/FolderListItem.axaml similarity index 62% rename from Views/Controls/CustomFolderListItem.axaml rename to Views/Controls/FolderListItem.axaml index 5a4872e..05fbfab 100644 --- a/Views/Controls/CustomFolderListItem.axaml +++ b/Views/Controls/FolderListItem.axaml @@ -10,9 +10,16 @@ - - + + + + + + + + + diff --git a/Views/Controls/CustomFolderListItem.axaml.cs b/Views/Controls/FolderListItem.axaml.cs similarity index 64% rename from Views/Controls/CustomFolderListItem.axaml.cs rename to Views/Controls/FolderListItem.axaml.cs index 4ccf1a1..e7040f1 100644 --- a/Views/Controls/CustomFolderListItem.axaml.cs +++ b/Views/Controls/FolderListItem.axaml.cs @@ -1,4 +1,5 @@ -using Avalonia.Controls; +using Avalonia; +using Avalonia.Controls; using Avalonia.Input; using Avalonia.Markup.Xaml; using OlibKey.Structures; @@ -10,9 +11,22 @@ public class FolderListItem : UserControl { public TextBox _tbName; private TextBlock _textName; + private TextBlock _tbDeleteDate; + public CheckBox SelectedItem; public Folder FolderContext => DataContext as Folder; public FolderListItem() => InitializeComponent(); + public FolderListItem(Folder f) + { + InitializeComponent(); + DataContext = f; + + if (!string.IsNullOrEmpty(FolderContext.DeleteDate)) + { + _tbDeleteDate.IsVisible = true; + _tbDeleteDate.Text = $"{(string)Application.Current.FindResource("Removed")} {FolderContext.DeleteDate}"; + } + } private void InitializeComponent() { @@ -20,6 +34,8 @@ private void InitializeComponent() _tbName = this.FindControl("tbName"); _textName = this.FindControl("textName"); + SelectedItem = this.FindControl("selectedItem"); + _tbDeleteDate = this.FindControl("tbDeleteDate"); _tbName.Focus(); _tbName.LostFocus += (s, e) => { _tbName.IsVisible = false; FolderContext.Name = _tbName.Text; _textName.Text = FolderContext.Name; }; diff --git a/Views/Controls/LoginListItem.axaml b/Views/Controls/LoginListItem.axaml index 28fdac7..9762a0d 100644 --- a/Views/Controls/LoginListItem.axaml +++ b/Views/Controls/LoginListItem.axaml @@ -8,19 +8,20 @@ Background="Transparent" Height="40" x:Class="OlibKey.Views.Controls.LoginListItem"> - - - - - - - - - + - - + + + + + + + + + + + diff --git a/Views/Controls/LoginListItem.axaml.cs b/Views/Controls/LoginListItem.axaml.cs index e70ce74..44ebb9f 100644 --- a/Views/Controls/LoginListItem.axaml.cs +++ b/Views/Controls/LoginListItem.axaml.cs @@ -6,14 +6,18 @@ using OlibKey.Structures; using OlibKey.Views.Windows; using System; +using Avalonia.Controls.Primitives; namespace OlibKey.Views.Controls { public class LoginListItem : UserControl { public Image IconLogin; + public CheckBox SelectedItem; + public ToggleButton IsFavorite; private readonly TextBlock _tbLoginName; private readonly TextBlock _tbUsername; + private TextBlock _tbDeleteDate; public string LoginID { get; set; } @@ -30,6 +34,9 @@ public LoginListItem(Login Login) IconLogin = this.FindControl("imageIconWebSite"); _tbLoginName = this.FindControl("tbLoginName"); _tbUsername = this.FindControl("tbUsername"); + SelectedItem = this.FindControl("selectedItem"); + IsFavorite = this.FindControl("isFavorite"); + _tbDeleteDate = this.FindControl("tbDeleteDate"); LoginItem = Login; @@ -49,22 +56,42 @@ public LoginListItem(Login Login) break; } - if (LoginItem.Type == 0 && string.IsNullOrEmpty(Login.Username)) _tbUsername.Text = Login.Email; + _tbUsername.Text = LoginItem.Type switch + { + 0 when string.IsNullOrEmpty(Login.Username) => Login.Email, + 4 => LoginItem.TimeCreate, + _ => _tbUsername.Text + }; + + if (!string.IsNullOrEmpty(LoginItem.DeleteDate)) + { + _tbDeleteDate.IsVisible = true; + _tbDeleteDate.Text = $"{(string)Application.Current.FindResource("Removed")} {LoginItem.DeleteDate}"; + Height = 60; + } + + IsFavorite.IsChecked = LoginItem.Favorite; + + IsFavorite.Checked += IsFavoriteChecking; + IsFavorite.Unchecked += IsFavoriteChecking; - if (LoginItem.Type == 4) _tbUsername.Text = LoginItem.TimeCreate; } - private void InitializeComponent() => AvaloniaXamlLoader.Load(this); + private void IsFavoriteChecking(object sender, Avalonia.Interactivity.RoutedEventArgs e) => LoginItem.Favorite = ((ToggleButton)sender).IsChecked ?? false; + + private void InitializeComponent() => AvaloniaXamlLoader.Load(this); public void EditedLogin() { if (LoginItem == null) return; _tbLoginName.Text = LoginItem.Name; - _tbUsername.Text = LoginItem.Username; - - if (LoginItem.Type == 0 && string.IsNullOrEmpty(LoginItem.Username)) _tbUsername.Text = LoginItem.Email; - if (LoginItem.Type == 4) _tbUsername.Text = LoginItem.TimeCreate; + _tbUsername.Text = LoginItem.Type switch + { + 0 when string.IsNullOrEmpty(LoginItem.Username) => LoginItem.Email, + 4 => LoginItem.TimeCreate, + _ => LoginItem.Username + }; } public async void GetIconElement() diff --git a/Views/Pages/CreateLoginPage.axaml b/Views/Pages/CreateLoginPage.axaml index ccd2f37..cd91504 100644 --- a/Views/Pages/CreateLoginPage.axaml +++ b/Views/Pages/CreateLoginPage.axaml @@ -6,12 +6,7 @@ xmlns:c="clr-namespace:OlibKey.Core;assembly=OlibKey" Background="{DynamicResource ThemeWindowBackgroundBrush}" x:Class="OlibKey.Views.Pages.CreateLoginPage"> - - - - - - + @@ -188,7 +183,7 @@ -