diff --git a/App.config b/App.config new file mode 100644 index 0000000..d19182c --- /dev/null +++ b/App.config @@ -0,0 +1,18 @@ + + + + +
+ + + + + + + + + + + + + diff --git a/App.xaml b/App.xaml new file mode 100644 index 0000000..e9821a3 --- /dev/null +++ b/App.xaml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/App.xaml.cs b/App.xaml.cs new file mode 100644 index 0000000..6df46e2 --- /dev/null +++ b/App.xaml.cs @@ -0,0 +1,43 @@ +using System.Data.SqlClient; +using System.Windows; +using DebtMgr.Data; +using DebtMgr.ViewModel; +using SQLite.Net; + +namespace DebtMgr +{ + /// + /// Interaktionslogik für "App.xaml" + /// + public partial class App : Application + { + #region Locator + + private static ViewModelLocator _locator; + public static ViewModelLocator Locator => _locator ?? (_locator = new ViewModelLocator()); + + #endregion + + #region Database + + private static SQLiteConnection _database; + public static SQLiteConnection Database => _database ?? (_database = new Database(DebtMgr.Properties.Settings.Default.Database)); + + #endregion + + #region DatabasePath + + private static string _databasePath; + public static string DatabasePath + { + get => _databasePath; + set + { + _database = null; + _databasePath = value; + } + } + + #endregion + } +} diff --git a/Content/addperson.ico b/Content/addperson.ico new file mode 100644 index 0000000..9282cde Binary files /dev/null and b/Content/addperson.ico differ diff --git a/Content/delete.ico b/Content/delete.ico new file mode 100644 index 0000000..3ce67cc Binary files /dev/null and b/Content/delete.ico differ diff --git a/Content/icon.ico b/Content/icon.ico new file mode 100644 index 0000000..dc70467 Binary files /dev/null and b/Content/icon.ico differ diff --git a/Content/moneybag.ico b/Content/moneybag.ico new file mode 100644 index 0000000..9e26bc0 Binary files /dev/null and b/Content/moneybag.ico differ diff --git a/Converters/AmountToColorConverter.cs b/Converters/AmountToColorConverter.cs new file mode 100644 index 0000000..c6f9887 --- /dev/null +++ b/Converters/AmountToColorConverter.cs @@ -0,0 +1,73 @@ +using System; +using System.Globalization; +using System.Windows.Data; +using System.Windows.Media; + +namespace DebtMgr.Converters +{ + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// An amount to color converter. + /// + /// Andre Beging, 10.09.2017. + //////////////////////////////////////////////////////////////////////////////////////////////////// + public class AmountToColorConverter : IValueConverter + { + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Converts. + /// + /// Andre Beging, 10.09.2017. + /// + /// The value. + /// Type of the target. + /// The parameter. + /// The culture. + /// + /// An object. + //////////////////////////////////////////////////////////////////////////////////////////////////// + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + var defaultReturnValue = new SolidColorBrush(Colors.Black); + if (value == null) return defaultReturnValue; + + + double doubleValue = 0.0; + if (value is double) + { + doubleValue = (double)value; + } + else if(value is string) + { + if (string.IsNullOrWhiteSpace(value.ToString())) return defaultReturnValue; + doubleValue = Double.Parse(value.ToString()); + } + + if (doubleValue < 0.001 && doubleValue > -0.001) + return new SolidColorBrush(Colors.Green); + + if(doubleValue > 0) + return new SolidColorBrush(Colors.Green); + + if (doubleValue < 0) + return new SolidColorBrush(Colors.Red); + + return defaultReturnValue; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Convert back. + /// + /// Andre Beging, 10.09.2017. + /// + /// The value. + /// Type of the target. + /// The parameter. + /// The culture. + /// + /// The back converted. + //////////////////////////////////////////////////////////////////////////////////////////////////// + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/CurrencyTextBoxControl.dll b/CurrencyTextBoxControl.dll new file mode 100644 index 0000000..392e4dd Binary files /dev/null and b/CurrencyTextBoxControl.dll differ diff --git a/Data/Database.cs b/Data/Database.cs new file mode 100644 index 0000000..5a7a4d4 --- /dev/null +++ b/Data/Database.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using DebtMgr.Model; +using SQLite.Net; +using SQLite.Net.Interop; +using SQLite.Net.Platform.Generic; + +namespace DebtMgr.Data +{ + public class Database : SQLiteConnection + { + #region Constructors + + public Database(ISQLitePlatform sqlitePlatform, string databasePath, bool storeDateTimeAsTicks = true, IBlobSerializer serializer = null, IDictionary tableMappings = null, IDictionary extraTypeMappings = null, IContractResolver resolver = null) : base(sqlitePlatform, databasePath, storeDateTimeAsTicks, serializer, tableMappings, extraTypeMappings, resolver) + { + } + + public Database(ISQLitePlatform sqlitePlatform, string databasePath, SQLiteOpenFlags openFlags, bool storeDateTimeAsTicks = true, IBlobSerializer serializer = null, IDictionary tableMappings = null, IDictionary extraTypeMappings = null, IContractResolver resolver = null) : base(sqlitePlatform, databasePath, openFlags, storeDateTimeAsTicks, serializer, tableMappings, extraTypeMappings, resolver) + { + } + + #endregion + + public Database(string databasePath) : base(new SQLitePlatformGeneric(), databasePath) + { + CreateTables(); + } + + #region CreateTables + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Creates the tables. + /// + /// Andre Beging, 08.09.2017. + //////////////////////////////////////////////////////////////////////////////////////////////////// + private void CreateTables() + { + CreateTable(); + CreateTable(); + } + + #endregion + } +} diff --git a/DebtMgr.csproj b/DebtMgr.csproj new file mode 100644 index 0000000..e883875 --- /dev/null +++ b/DebtMgr.csproj @@ -0,0 +1,188 @@ + + + + + Debug + AnyCPU + {11FFBAAB-CE28-4B77-8C7A-8B15F0007133} + WinExe + DebtMgr + DebtMgr + v4.6 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + true + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + Content\icon.ico + + + + .\CurrencyTextBoxControl.dll + + + packages\MvvmLightLibs.5.3.0.0\lib\net45\GalaSoft.MvvmLight.dll + + + packages\MvvmLightLibs.5.3.0.0\lib\net45\GalaSoft.MvvmLight.Extras.dll + + + packages\MvvmLightLibs.5.3.0.0\lib\net45\GalaSoft.MvvmLight.Platform.dll + + + packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll + + + packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll + + + packages\SQLite.Net-PCL.3.0.5\lib\net40\SQLite.Net.dll + + + packages\SQLite.Net-PCL.3.0.5\lib\net40\SQLite.Net.Platform.Generic.dll + + + packages\SQLite.Net-PCL.3.0.5\lib\net4\SQLite.Net.Platform.Win32.dll + + + packages\SQLiteNetExtensions.1.3.0\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1\SQLiteNetExtensions.dll + + + + + packages\MvvmLightLibs.5.3.0.0\lib\net45\System.Windows.Interactivity.dll + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + + + + + + + + + + + + AddTransactionView.xaml + + + DatabaseSelectorDialogView.xaml + + + NewPersonDialogView.xaml + + + MainView.xaml + + + App.xaml + Code + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + Always + + + + + + + + + + + + + + + + + Always + + + + \ No newline at end of file diff --git a/DebtMgr.sln b/DebtMgr.sln new file mode 100644 index 0000000..4690b4c --- /dev/null +++ b/DebtMgr.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26430.13 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DebtMgr", "DebtMgr.csproj", "{11FFBAAB-CE28-4B77-8C7A-8B15F0007133}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {11FFBAAB-CE28-4B77-8C7A-8B15F0007133}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {11FFBAAB-CE28-4B77-8C7A-8B15F0007133}.Debug|Any CPU.Build.0 = Debug|Any CPU + {11FFBAAB-CE28-4B77-8C7A-8B15F0007133}.Release|Any CPU.ActiveCfg = Release|Any CPU + {11FFBAAB-CE28-4B77-8C7A-8B15F0007133}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Extensions/ExtensionMethods.cs b/Extensions/ExtensionMethods.cs new file mode 100644 index 0000000..4429b38 --- /dev/null +++ b/Extensions/ExtensionMethods.cs @@ -0,0 +1,54 @@ +using System.Globalization; +using System.Windows; + +namespace DebtMgr.Extensions +{ + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// An extension methods. + /// + /// Andre Beging, 10.09.2017. + //////////////////////////////////////////////////////////////////////////////////////////////////// + public static class ExtensionMethods + { + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Centers the current window on parent + /// + /// Andre Beging, 08.09.2017. + /// + /// The window to act on. + //////////////////////////////////////////////////////////////////////////////////////////////////// + public static void CenterOnParent(this Window window) + { + var curApp = Application.Current; + var mainWindow = curApp.MainWindow; + window.Left = mainWindow.Left + (mainWindow.Width - window.ActualWidth) / 2 - (window.Width / 2); + window.Top = mainWindow.Top + (mainWindow.Height - window.ActualHeight) / 2 - (window.Height / 2); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// A string extension method that gets a double. + /// + /// Andre Beging, 09.09.2017. + /// + /// The value to act on. + /// The default value. + /// + /// The double. + //////////////////////////////////////////////////////////////////////////////////////////////////// + public static double GetDouble(this string value, double defaultValue) + { + double result; + + // Try parsing in the current culture + if (!double.TryParse(value, NumberStyles.Any, CultureInfo.CurrentCulture, out result) && + // Then try in US english + !double.TryParse(value, NumberStyles.Any, CultureInfo.GetCultureInfo("en-US"), out result) && + // Then in neutral language + !double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out result)) + { + result = defaultValue; + } + return result; + } + } +} diff --git a/Model/Enums.cs b/Model/Enums.cs new file mode 100644 index 0000000..c51cd62 --- /dev/null +++ b/Model/Enums.cs @@ -0,0 +1,19 @@ +using System.ComponentModel; + +namespace DebtMgr.Model +{ + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Values that represent transaction types. + /// + /// Andre Beging, 08.09.2017. + //////////////////////////////////////////////////////////////////////////////////////////////////// + public enum TransactionType + { + [Description("None")] + None, + [Description("Deposit")] + Deposit, + [Description("Charge")] + Charge + } +} diff --git a/Model/Person.cs b/Model/Person.cs new file mode 100644 index 0000000..9a07d76 --- /dev/null +++ b/Model/Person.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SQLite.Net.Attributes; +using SQLiteNetExtensions.Attributes; + +namespace DebtMgr.Model +{ + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// A person. + /// + /// Andre Beging, 10.09.2017. + //////////////////////////////////////////////////////////////////////////////////////////////////// + public class Person + { + #region Id + + [PrimaryKey] + public Guid Id { get; set; } = Guid.NewGuid(); + + #endregion + + #region Transaction Relation + + [OneToMany(CascadeOperations = CascadeOperation.All)] + public List Transactions { get; set; } = new List(); + + #endregion + + #region Total + + /// Transaction Total + public double Total + { + get + { + var sum = 0.0; + + foreach (var transaction in Transactions) + { + if (transaction.Type == TransactionType.Charge) + sum -= transaction.Amount; + else if (transaction.Type == TransactionType.Deposit) + sum += transaction.Amount; + + } + + return sum; + } + } + + #endregion + + #region FirstName + + public string FirstName { get; set; } + + #endregion + + #region LastName + + public string LastName { get; set; } + + #endregion + + #region ToString() + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Convert this object into a string representation. + /// + /// Andre Beging, 09.09.2017. + /// + /// A string that represents this object. + //////////////////////////////////////////////////////////////////////////////////////////////////// + public override string ToString() + { + return string.Format("{0} {1}", FirstName, LastName); + } + + #endregion + } +} diff --git a/Model/Transaction.cs b/Model/Transaction.cs new file mode 100644 index 0000000..e4cc7b2 --- /dev/null +++ b/Model/Transaction.cs @@ -0,0 +1,93 @@ +using System; +using System.ComponentModel; +using SQLite.Net.Attributes; +using SQLiteNetExtensions.Attributes; + +namespace DebtMgr.Model +{ + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// A transaction. + /// + /// Andre Beging, 10.09.2017. + //////////////////////////////////////////////////////////////////////////////////////////////////// + public class Transaction + { + #region Id + + [PrimaryKey] + public Guid Id { get; set; } = Guid.NewGuid(); + + #endregion + + #region Person Relation + + [ForeignKey(typeof(Person))] + public Guid PersonId { get; set; } + + [ManyToOne] + public Person Person { get; set; } + + #endregion + + #region Description + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Gets or sets the description. + /// + /// The description. + //////////////////////////////////////////////////////////////////////////////////////////////////// + public string Description { get; set; } + + #endregion + + #region Type + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Gets or sets the type. + /// + /// The type. + //////////////////////////////////////////////////////////////////////////////////////////////////// + public TransactionType Type + { + get + { + if (!string.IsNullOrWhiteSpace(StringType)) + { + return (TransactionType)Enum.Parse(typeof(TransactionType), StringType); + } + return TransactionType.None; + + } + set { StringType = value.ToString(); } + } + + public string StringType; + #endregion + + #region Time + + public DateTime Time { get; set; } + + #endregion + + #region Amount + + public double Amount { get; set; } + + #endregion + + #region SignedAmount + + [Ignore] + public double SignedAmount + { + get + { + if (Type == TransactionType.Charge) return Amount * -1; + return Amount; + } + } + + #endregion + } +} diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..b177b26 --- /dev/null +++ b/Properties/AssemblyInfo.cs @@ -0,0 +1,53 @@ +using System.Reflection; +using System.Runtime.InteropServices; +using System.Windows; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die einer Assembly zugeordnet sind. +[assembly: AssemblyTitle("DebtMgr")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("DebtMgr")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly +// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von +// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen. +[assembly: ComVisible(false)] + +//Um mit dem Erstellen lokalisierbarer Anwendungen zu beginnen, legen Sie +//ImCodeVerwendeteKultur in der .csproj-Datei +//in einer fest. Wenn Sie in den Quelldateien beispielsweise Deutsch +//(Deutschland) verwenden, legen Sie auf \"de-DE\" fest. Heben Sie dann die Auskommentierung +//des nachstehenden NeutralResourceLanguage-Attributs auf. Aktualisieren Sie "en-US" in der nachstehenden Zeile, +//sodass es mit der UICulture-Einstellung in der Projektdatei übereinstimmt. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //Speicherort der designspezifischen Ressourcenwörterbücher + //(wird verwendet, wenn eine Ressource auf der Seite nicht gefunden wird, + // oder in den Anwendungsressourcen-Wörterbüchern nicht gefunden werden kann.) + ResourceDictionaryLocation.SourceAssembly //Speicherort des generischen Ressourcenwörterbuchs + //(wird verwendet, wenn eine Ressource auf der Seite nicht gefunden wird, + // designspezifischen Ressourcenwörterbuch nicht gefunden werden kann.) +)] + + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden, +// übernehmen, indem Sie "*" eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Properties/Resources.Designer.cs b/Properties/Resources.Designer.cs new file mode 100644 index 0000000..ce52b19 --- /dev/null +++ b/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.42000 +// +// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +// der Code erneut generiert wird. +// +//------------------------------------------------------------------------------ + +namespace DebtMgr.Properties { + using System; + + + /// + /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. + /// + // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert + // -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert. + // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen + // mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DebtMgr.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle + /// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/Properties/Resources.resx b/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Properties/Settings.Designer.cs b/Properties/Settings.Designer.cs new file mode 100644 index 0000000..f6c9a86 --- /dev/null +++ b/Properties/Settings.Designer.cs @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +// +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.42000 +// +// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +// der Code erneut generiert wird. +// +//------------------------------------------------------------------------------ + +namespace DebtMgr.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.1.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string Database { + get { + return ((string)(this["Database"])); + } + set { + this["Database"] = value; + } + } + } +} diff --git a/Properties/Settings.settings b/Properties/Settings.settings new file mode 100644 index 0000000..a1eccb8 --- /dev/null +++ b/Properties/Settings.settings @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/View/Dialogs/AddTransactionView.xaml b/View/Dialogs/AddTransactionView.xaml new file mode 100644 index 0000000..5f9815d --- /dev/null +++ b/View/Dialogs/AddTransactionView.xaml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/View/Dialogs/AddTransactionView.xaml.cs b/View/Dialogs/AddTransactionView.xaml.cs new file mode 100644 index 0000000..0b85d3a --- /dev/null +++ b/View/Dialogs/AddTransactionView.xaml.cs @@ -0,0 +1,58 @@ +using DebtMgr.Extensions; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using DebtMgr.Model; + +namespace DebtMgr.View.Dialogs +{ + /// + /// Interaktionslogik für AddTransactionView.xaml + /// + public partial class AddTransactionView : Window + { + public AddTransactionView(TransactionType transactionType, Person preselectedPerson) + { + InitializeComponent(); + this.CenterOnParent(); + + App.Locator.AddTransactionView.ClearView(); + + App.Locator.AddTransactionView.DialogMode = transactionType; + App.Locator.AddTransactionView.PreselectedPerson = preselectedPerson; + App.Locator.AddTransactionView.SetModeSpecificStrings(); + + App.Locator.AddTransactionView.RequestClose += (s, e) => Close(); + + DataContext = App.Locator.AddTransactionView; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Event handler. Called by TextBox for on key up events. + /// + /// Andre Beging, 09.09.2017. + /// + /// Source of the event. + /// Key event information. + //////////////////////////////////////////////////////////////////////////////////////////////////// + private void TextBox_OnKeyUp(object sender, KeyEventArgs e) + { + if (e.Key.Equals(Key.Enter) || e.Key.Equals(Key.Return)) + App.Locator.AddTransactionView.AddTransactionButtonClickCommand.Execute(null); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Event handler. Called by Window for on key up events. + /// + /// Andre Beging, 09.09.2017. + /// + /// Source of the event. + /// Key event information. + //////////////////////////////////////////////////////////////////////////////////////////////////// + private void Window_OnKeyUp(object sender, KeyEventArgs e) + { + if (e.Key.Equals(Key.Escape)) + Close(); + } + } +} diff --git a/View/Dialogs/DatabaseSelectorDialogView.xaml b/View/Dialogs/DatabaseSelectorDialogView.xaml new file mode 100644 index 0000000..99523b1 --- /dev/null +++ b/View/Dialogs/DatabaseSelectorDialogView.xaml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/View/Dialogs/DatabaseSelectorDialogView.xaml.cs b/View/Dialogs/DatabaseSelectorDialogView.xaml.cs new file mode 100644 index 0000000..ed90a62 --- /dev/null +++ b/View/Dialogs/DatabaseSelectorDialogView.xaml.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; +using DebtMgr.Extensions; + +namespace DebtMgr.View.Dialogs +{ + /// + /// Interaktionslogik für DatabaseSelectorDialogView.xaml + /// + public partial class DatabaseSelectorDialogView : Window + { + public DatabaseSelectorDialogView() + { + InitializeComponent(); + + this.CenterOnParent(); + + App.Locator.DatabaseSelectorDialogView.RequestClose += (s, e) => Close(); + DataContext = App.Locator.DatabaseSelectorDialogView; + } + + private void Window_OnKeyUp(object sender, KeyEventArgs e) + { + if (e.Key.Equals(Key.Escape)) + Application.Current.Shutdown(); + } + } +} diff --git a/View/Dialogs/NewPersonDialogView.xaml b/View/Dialogs/NewPersonDialogView.xaml new file mode 100644 index 0000000..fc3bd5f --- /dev/null +++ b/View/Dialogs/NewPersonDialogView.xaml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/View/Dialogs/NewPersonDialogView.xaml.cs b/View/Dialogs/NewPersonDialogView.xaml.cs new file mode 100644 index 0000000..146d0fd --- /dev/null +++ b/View/Dialogs/NewPersonDialogView.xaml.cs @@ -0,0 +1,51 @@ +using System.Windows; +using System.Windows.Input; +using DebtMgr.Extensions; + +namespace DebtMgr.View.Dialogs +{ + /// + /// Interaktionslogik für NewPersonDialogView.xaml + /// + public partial class NewPersonDialogView : Window + { + public NewPersonDialogView() + { + InitializeComponent(); + this.CenterOnParent(); + + App.Locator.NewPersonDialogView.RequestClose += (s, e) => Close(); + DataContext = App.Locator.NewPersonDialogView; + + FirstNameTextBox.Focus(); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Event handler. Called by TextBox for on key up events. + /// + /// Andre Beging, 09.09.2017. + /// + /// Source of the event. + /// Key event information. + //////////////////////////////////////////////////////////////////////////////////////////////////// + private void TextBox_OnKeyUp(object sender, KeyEventArgs e) + { + if (e.Key.Equals(Key.Enter) || e.Key.Equals(Key.Return)) + App.Locator.NewPersonDialogView.CreatePersonButtonClickCommand.Execute(null); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Event handler. Called by Window for key up events. + /// + /// Andre Beging, 09.09.2017. + /// + /// Source of the event. + /// Key event information. + //////////////////////////////////////////////////////////////////////////////////////////////////// + private void Window_KeyUp(object sender, KeyEventArgs e) + { + if (e.Key.Equals(Key.Escape)) + Close(); + } + } +} diff --git a/View/MainView.xaml b/View/MainView.xaml new file mode 100644 index 0000000..66005b2 --- /dev/null +++ b/View/MainView.xaml @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + First name + + + Last name + + + Balance + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/View/MainView.xaml.cs b/View/MainView.xaml.cs new file mode 100644 index 0000000..df547d6 --- /dev/null +++ b/View/MainView.xaml.cs @@ -0,0 +1,68 @@ +using System; +using System.Windows; +using System.Windows.Input; + +namespace DebtMgr.View +{ + /// + /// Interaktionslogik für MainView.xaml + /// + public partial class MainView : Window + { + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Default constructor. + /// + /// Andre Beging, 10.09.2017. + //////////////////////////////////////////////////////////////////////////////////////////////////// + public MainView() + { + InitializeComponent(); + DataContext = App.Locator.MainView; + + PersonListView.KeyUp += PersonListViewOnKeyUp; + TransactionHistoryListView.KeyUp += TransactionHistoryListViewOnKeyUp; + } + + #region PersonListViewOnKeyUp() + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Person list view on key up. + /// + /// Andre Beging, 10.09.2017. + /// + /// Source of the event. + /// Key event information. + //////////////////////////////////////////////////////////////////////////////////////////////////// + private void PersonListViewOnKeyUp(object sender, KeyEventArgs e) + { + if (e.Key == Key.Delete) + { + if (App.Locator.MainView.DeletePersonContextMenuCommand.CanExecute(null)) + App.Locator.MainView.DeletePersonContextMenuCommand.Execute(null); + } + + } + + #endregion + #region TransactionHistoryListViewOnKeyUp() + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Transaction history list view on key up. + /// + /// Andre Beging, 10.09.2017. + /// + /// Source of the event. + /// Key event information. + //////////////////////////////////////////////////////////////////////////////////////////////////// + private void TransactionHistoryListViewOnKeyUp(object sender, KeyEventArgs e) + { + if (e.Key == Key.Delete) + { + if (App.Locator.MainView.DeleteTransactionContextMenuCommand.CanExecute(null)) + App.Locator.MainView.DeleteTransactionContextMenuCommand.Execute(null); + } + } + + #endregion + } +} diff --git a/ViewModel/Dialogs/AddDepositViewModel.cs b/ViewModel/Dialogs/AddDepositViewModel.cs new file mode 100644 index 0000000..d27f721 --- /dev/null +++ b/ViewModel/Dialogs/AddDepositViewModel.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using GalaSoft.MvvmLight; + +namespace DebtMgr.ViewModel.Dialogs +{ + public class AddTransactionViewModel : ViewModelBase + { + } +} diff --git a/ViewModel/Dialogs/AddTransactionViewModel.cs b/ViewModel/Dialogs/AddTransactionViewModel.cs new file mode 100644 index 0000000..6fc95e0 --- /dev/null +++ b/ViewModel/Dialogs/AddTransactionViewModel.cs @@ -0,0 +1,301 @@ +using DebtMgr.Model; +using GalaSoft.MvvmLight; +using GalaSoft.MvvmLight.Command; +using SQLiteNetExtensions.Extensions; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Windows; + +namespace DebtMgr.ViewModel.Dialogs +{ + public class AddTransactionViewModel : ViewModelBase + { + #region Public Properties + + public event EventHandler RequestClose; + public TransactionType DialogMode { get; set; } + + public Person PreselectedPerson { get; set; } + + #endregion + + #region WindowTitle (string) Property + + /// + /// Privater Teil von + /// + private string _windowTitle; + + /// + /// Comment + /// + public string WindowTitle + { + get { return _windowTitle; } + + set + { + _windowTitle = value; + RaisePropertyChanged(() => WindowTitle); + } + } + + #endregion + + #region AmountTextBoxText (string) Property + + /// + /// Privater Teil von + /// + private string _amountTextBoxText; + + /// + /// Comment + /// + public string AmountTextBoxText + { + get + { + return _amountTextBoxText; + } + + set + { + _amountTextBoxText = value; + RaisePropertyChanged(() => AmountTextBoxText); + AddTransactionButtonClickCommand.RaiseCanExecuteChanged(); + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Gets the amount text box text as number representation. + /// + /// The amount text box text number representation. + //////////////////////////////////////////////////////////////////////////////////////////////////// + public double AmountTextBoxTextNumberRepresentation + { + get + { + if (string.IsNullOrWhiteSpace(_amountTextBoxText)) return 0.0; + return double.Parse(_amountTextBoxText, CultureInfo.InvariantCulture); + } + } + + #endregion + #region DescriptionTextBoxText (string) Property + + /// + /// Privater Teil von + /// + private string _descriptionTextBoxText; + + /// + /// DescriptionTextBoxText + /// + public string DescriptionTextBoxText + { + get { return _descriptionTextBoxText; } + + set + { + _descriptionTextBoxText = value; + RaisePropertyChanged(() => DescriptionTextBoxText); + AddTransactionButtonClickCommand.RaiseCanExecuteChanged(); + } + } + + #endregion + #region DatePickerSelectedDate (DateTime?) Property + + /// + /// Privater Teil von + /// + private DateTime? _datePickerSelectedDate; + + /// + /// Comment + /// + public DateTime? DatePickerSelectedDate + { + get { return _datePickerSelectedDate; } + + set + { + _datePickerSelectedDate = value; + RaisePropertyChanged(() => DatePickerSelectedDate); + AddTransactionButtonClickCommand.RaiseCanExecuteChanged(); + } + } + + #endregion + + #region PersonComboBoxItemSource (List) Property + + /// + /// Privater Teil von + /// + private List _personComboBoxItemSource; + + /// + /// Comment + /// + public List PersonComboBoxItemSource + { + get { return _personComboBoxItemSource; } + + set + { + _personComboBoxItemSource = value; + RaisePropertyChanged(() => PersonComboBoxItemSource); + } + } + + #endregion + #region PersonComboBoxSelectedItem (Person) Property + + /// + /// Privater Teil von + /// + private Person _personComboBoxSelectedItem; + + /// + /// Comment + /// + public Person PersonComboBoxSelectedItem + { + get { return _personComboBoxSelectedItem; } + + set + { + _personComboBoxSelectedItem = value; + RaisePropertyChanged(() => PersonComboBoxSelectedItem); + AddTransactionButtonClickCommand.RaiseCanExecuteChanged(); + } + } + + #endregion + + #region AddTransactionButtonClickCommand Command + + /// + /// Private member backing variable for + /// + private RelayCommand _addTransactionButtonClickCommand = null; + + /// + /// Comment + /// + public RelayCommand AddTransactionButtonClickCommand => _addTransactionButtonClickCommand ?? (_addTransactionButtonClickCommand = new RelayCommand(AddTransactionButtonClickCommand_Execute, AddTransactionButtonClickCommand_CanExecute)); + + private bool AddTransactionButtonClickCommand_CanExecute() + { + if (AmountTextBoxTextNumberRepresentation < 0.01) return false; + if (string.IsNullOrWhiteSpace(DescriptionTextBoxText)) return false; + if (PersonComboBoxSelectedItem == null) return false; + if (DatePickerSelectedDate == null) return false; + + return true; + } + + private void AddTransactionButtonClickCommand_Execute() + { + if (AddTransactionButtonClickCommand_CanExecute()) + { + try + { + var person = App.Database.Get(PersonComboBoxSelectedItem.Id); + App.Database.GetChildren(person); + + if (DatePickerSelectedDate != null) + person.Transactions.Add(new Transaction + { + Amount = AmountTextBoxTextNumberRepresentation, + Type = DialogMode, + Description = DescriptionTextBoxText, + PersonId = person.Id, + Time = DatePickerSelectedDate.Value + }); + + App.Database.InsertOrReplaceWithChildren(person); + RequestClose?.Invoke(null, null); + App.Locator.MainView.UpdatePersonsList(); + } + catch (Exception) + { + MessageBox.Show("Something bad happened", "Error", MessageBoxButton.OK, MessageBoxImage.Error); + } + + + } + } + + #endregion + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Default constructor. + /// + /// Andre Beging, 10.09.2017. + //////////////////////////////////////////////////////////////////////////////////////////////////// + public AddTransactionViewModel() + { + UpdatesPersonsComboBox(); + } + + #region UpdatesPersonsComboBox() + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Updates persons combo box. + /// + /// Andre Beging, 09.09.2017. + //////////////////////////////////////////////////////////////////////////////////////////////////// + public void UpdatesPersonsComboBox() + { + var personList = App.Database.Table().OrderBy(x => x.FirstName).ToList(); + PersonComboBoxItemSource = personList; + } + + #endregion + #region SetModeSpecificStrings() + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Sets mode specific strings. + /// + /// Andre Beging, 09.09.2017. + //////////////////////////////////////////////////////////////////////////////////////////////////// + public void SetModeSpecificStrings() + { + if (DialogMode == TransactionType.Deposit) + { + WindowTitle = "Add Deposit"; + } + + if (DialogMode == TransactionType.Charge) + { + WindowTitle = "Add Charge"; + } + + PersonComboBoxSelectedItem = + PersonComboBoxItemSource.FirstOrDefault(x => x.Id == PreselectedPerson?.Id); + } + + #endregion + #region ClearView() + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Clears the view. + /// + /// Andre Beging, 09.09.2017. + //////////////////////////////////////////////////////////////////////////////////////////////////// + public void ClearView() + { + AmountTextBoxText = string.Empty; + DescriptionTextBoxText = string.Empty; + PersonComboBoxSelectedItem = null; + DatePickerSelectedDate = DateTime.Now; + } + + #endregion + } +} diff --git a/ViewModel/Dialogs/DatabaseSelectorDialogViewModel.cs b/ViewModel/Dialogs/DatabaseSelectorDialogViewModel.cs new file mode 100644 index 0000000..c383ca1 --- /dev/null +++ b/ViewModel/Dialogs/DatabaseSelectorDialogViewModel.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using DebtMgr.Model; +using GalaSoft.MvvmLight; +using GalaSoft.MvvmLight.Command; +using Microsoft.Win32; +using SQLite.Net; +using SQLite.Net.Platform.Generic; + +namespace DebtMgr.ViewModel.Dialogs +{ + public class DatabaseSelectorDialogViewModel : ViewModelBase + { + public event EventHandler RequestClose; + + #region SelectDatabasePathText (string) Property + + /// + /// Privater Teil von + /// + private string _selectDatabasePathText; + + /// + /// Comment + /// + public string SelectDatabasePathText + { + get { return _selectDatabasePathText; } + + set + { + _selectDatabasePathText = value; + RaisePropertyChanged(() => SelectDatabasePathText); + } + } + + #endregion + + #region SelectDatabaseButtonClick Command + + /// + /// Private member backing variable for + /// + private RelayCommand _selectDatabaseButtonClick = null; + + /// + /// Comment + /// + public RelayCommand SelectDatabaseButtonClick => _selectDatabaseButtonClick ?? (_selectDatabaseButtonClick = new RelayCommand(SelectDatabaseButtonClick_Execute)); + + private void SelectDatabaseButtonClick_Execute() + { + var openFileDialog = new OpenFileDialog(); + openFileDialog.CheckFileExists = true; + openFileDialog.Filter = "Debt Manager Database|*.dmdb|All files|*.*"; + + //Application.Current.Shutdown(); + + if (openFileDialog.ShowDialog() == true) + { + var x = new SQLiteConnection(new SQLitePlatformGeneric(), openFileDialog.FileName); + + try + { + x.Table().ToList(); + + Properties.Settings.Default["Database"] = openFileDialog.FileName; + Properties.Settings.Default.Save(); + + RequestClose?.Invoke(null, null); + } + catch (Exception) + { + MessageBox.Show( + string.Format("File is not a Debt Manager database\n\n{0}", openFileDialog.FileName), + "File invalid", + MessageBoxButton.OK, + MessageBoxImage.Error); + } + finally + { + x.Close(); + } + } + + } + + #endregion + #region CreateDatabaseButtonClick Command + + /// + /// Private member backing variable for + /// + private RelayCommand _createDatabaseButtonClick = null; + + /// + /// Comment + /// + public RelayCommand CreateDatabaseButtonClick => _createDatabaseButtonClick ?? (_createDatabaseButtonClick = new RelayCommand(CreateDatabaseButtonClick_Execute)); + + private void CreateDatabaseButtonClick_Execute() + { + var saveFileDialog = new SaveFileDialog(); + saveFileDialog.Filter = "Debt Manager Database|*.dmdb|Standard database|*.db"; + saveFileDialog.CreatePrompt = true; + + if (saveFileDialog.ShowDialog() == true) + { + Properties.Settings.Default["Database"] = saveFileDialog.FileName; + Properties.Settings.Default.Save(); + + RequestClose?.Invoke(null, null); + } + } + + #endregion + + + } +} diff --git a/ViewModel/Dialogs/NewPersonDialogViewModel.cs b/ViewModel/Dialogs/NewPersonDialogViewModel.cs new file mode 100644 index 0000000..e4da540 --- /dev/null +++ b/ViewModel/Dialogs/NewPersonDialogViewModel.cs @@ -0,0 +1,125 @@ +using System; +using System.Windows; +using DebtMgr.Model; +using GalaSoft.MvvmLight; +using GalaSoft.MvvmLight.Command; + +namespace DebtMgr.ViewModel.Dialogs +{ + public class NewPersonDialogViewModel : ViewModelBase + { + public event EventHandler RequestClose; + + #region FirstNameTextBoxText (string) Property + + /// + /// Privater Teil von + /// + private string _firstNameTextBoxText; + + /// + /// Comment + /// + public string FirstNameTextBoxText + { + get { return _firstNameTextBoxText; } + + set + { + _firstNameTextBoxText = value; + RaisePropertyChanged(() => FirstNameTextBoxText); + CreatePersonButtonClickCommand.RaiseCanExecuteChanged(); + } + } + + #endregion + #region LastNameTextBoxText (string) Property + + /// + /// Privater Teil von + /// + private string _lastNameTextBoxText; + + /// + /// Comment + /// + public string LastNameTextBoxText + { + get { return _lastNameTextBoxText; } + + set + { + _lastNameTextBoxText = value; + RaisePropertyChanged(() => LastNameTextBoxText); + CreatePersonButtonClickCommand.RaiseCanExecuteChanged(); + } + } + + #endregion + + #region CreatePersonButtonClickCommand Command + + /// + /// Private member backing variable for + /// + private RelayCommand _createPersonButtonClickCommand = null; + + /// + /// Comment + /// + public RelayCommand CreatePersonButtonClickCommand => _createPersonButtonClickCommand ?? (_createPersonButtonClickCommand = new RelayCommand(CreatePersonButtonClickCommand_Execute, CreatePersonButtonClickCommand_CanExecute)); + + private bool CreatePersonButtonClickCommand_CanExecute() + { + if (string.IsNullOrWhiteSpace(FirstNameTextBoxText) || string.IsNullOrWhiteSpace(LastNameTextBoxText)) + { + return false; + } + return true; + } + + private void CreatePersonButtonClickCommand_Execute() + { + if (CreatePersonButtonClickCommand_CanExecute()) + { + var newPerson = new Person + { + FirstName = FirstNameTextBoxText, + LastName = LastNameTextBoxText + }; + + var resultId = App.Database.Insert(newPerson); + + if (resultId == 1) + { + App.Locator.MainView.UpdatePersonsList(); + App.Locator.AddTransactionView.UpdatesPersonsComboBox(); + RequestClose?.Invoke(null, null); + ClearView(); + } + else + { + MessageBox.Show("Something bad happened", "Error", MessageBoxButton.OK, MessageBoxImage.Error); + } + } + } + + #endregion + + #region ClearView() + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Clears the view. + /// + /// Andre Beging, 08.09.2017. + //////////////////////////////////////////////////////////////////////////////////////////////////// + private void ClearView() + { + FirstNameTextBoxText = string.Empty; + LastNameTextBoxText = string.Empty; + } + + #endregion + + } +} diff --git a/ViewModel/MainViewModel.cs b/ViewModel/MainViewModel.cs new file mode 100644 index 0000000..abf8a3e --- /dev/null +++ b/ViewModel/MainViewModel.cs @@ -0,0 +1,488 @@ +using DebtMgr.Model; +using DebtMgr.View.Dialogs; +using GalaSoft.MvvmLight; +using GalaSoft.MvvmLight.Command; +using SQLiteNetExtensions.Extensions; +using System.Collections.Generic; +using System.Linq; +using System.Windows; +using System; +using System.Configuration; +using SQLite.Net; +using SQLite.Net.Platform.Generic; + +namespace DebtMgr.ViewModel +{ + public class MainViewModel : ViewModelBase + { + #region PersonListViewItemSource (List) Property + + /// + /// Privater Teil von + /// + private List _personListViewItemSource; + + /// + /// Comment + /// + public List PersonListViewItemSource + { + get { return _personListViewItemSource; } + + set + { + _personListViewItemSource = value; + RaisePropertyChanged(() => PersonListViewItemSource); + } + } + + #endregion + #region PersonListViewSelectedItem (Person) Property + + /// + /// Privater Teil von + /// + private Person _personListViewSelectedItem; + + /// + /// PersonListViewSelectedItem + /// + public Person PersonListViewSelectedItem + { + get { return _personListViewSelectedItem; } + + set + { + _personListViewSelectedItem = value; + RaisePropertyChanged(() => PersonListViewSelectedItem); + DeletePersonContextMenuCommand.RaiseCanExecuteChanged(); + + UpdateDetailView(); + } + } + + + + #endregion + + #region DetailViewHeaderLabelContent (string) Property + + /// + /// Privater Teil von + /// + private string _detailViewHeaderLabelContent; + + /// + /// Comment + /// + public string DetailViewHeaderLabelContent + { + get { return _detailViewHeaderLabelContent; } + + set + { + _detailViewHeaderLabelContent = value; + RaisePropertyChanged(() => DetailViewHeaderLabelContent); + } + } + + #endregion + #region DetailViewBalanceLabel (string) Property + + /// + /// Privater Teil von + /// + private string _detailViewBalanceLabel; + + /// + /// Comment + /// + public string DetailViewBalanceLabel + { + get { return _detailViewBalanceLabel; } + + set + { + _detailViewBalanceLabel = value; + RaisePropertyChanged(() => DetailViewBalanceLabel); + } + } + + #endregion + + #region OverallBalanceLabel (string) Property + + /// + /// Privater Teil von + /// + private string _overallBalanceLabel; + + /// + /// Comment + /// + public string OverallBalanceLabel + { + get { return _overallBalanceLabel; } + + set + { + _overallBalanceLabel = value; + RaisePropertyChanged(() => OverallBalanceLabel); + } + } + + #endregion + + #region TransactionHistoryListViewItemSource (List) Property + + /// + /// Privater Teil von + /// + private List _transactionHistoryListViewItemSource; + + /// + /// Comment + /// + public List TransactionHistoryListViewItemSource + { + get { return _transactionHistoryListViewItemSource; } + + set + { + _transactionHistoryListViewItemSource = value; + RaisePropertyChanged(() => TransactionHistoryListViewItemSource); + } + } + + #endregion + #region TransactionHistoryListViewSelectedItem (Transaction) Property + + /// + /// Privater Teil von + /// + private Transaction _transactionHistoryListViewSelectedItem; + + /// + /// Comment + /// + public Transaction TransactionHistoryListViewSelectedItem + { + get { return _transactionHistoryListViewSelectedItem; } + + set + { + _transactionHistoryListViewSelectedItem = value; + RaisePropertyChanged(() => TransactionHistoryListViewSelectedItem); + DeleteTransactionContextMenuCommand.RaiseCanExecuteChanged(); + } + } + + #endregion + + #region MenuNewPersonCommand Command + + /// + /// Private member backing variable for + /// + private RelayCommand _menuNewPersonCommand = null; + + /// + /// Comment + /// + public RelayCommand MenuNewPersonCommand => _menuNewPersonCommand ?? (_menuNewPersonCommand = new RelayCommand(MenuNewPersonCommand_Execute, MenuNewPersonCommand_CanExecute)); + + private bool MenuNewPersonCommand_CanExecute() + { + return true; + } + + private void MenuNewPersonCommand_Execute() + { + var window = new NewPersonDialogView(); + window.ShowDialog(); + } + + #endregion + #region SortPersonListViewCommand + + /// The sort person list view command. + private RelayCommand _sortPersonListViewCommand = null; + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Gets the sort person list view command. + /// + /// The sort person list view command. + //////////////////////////////////////////////////////////////////////////////////////////////////// + public RelayCommand SortPersonListViewCommand + { + get + { + if (_sortPersonListViewCommand == null) + _sortPersonListViewCommand = new RelayCommand(SortPersonListViewCommand_Execute); + + return _sortPersonListViewCommand; + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Sort person list view command execute. + /// + /// Andre Beging, 08.09.2017. + /// + /// Name of the column. + //////////////////////////////////////////////////////////////////////////////////////////////////// + private void SortPersonListViewCommand_Execute(string columnName) + { + if (string.IsNullOrWhiteSpace(columnName)) return; + + switch (columnName) + { + case "FirstName": + PersonListViewItemSource = PersonListViewItemSource.OrderBy(x => x.FirstName).ToList(); + break; + case "LastName": + PersonListViewItemSource = PersonListViewItemSource.OrderBy(x => x.LastName).ToList(); + break; + case "Total": + PersonListViewItemSource = PersonListViewItemSource.OrderBy(x => x.Total).ToList(); + break; + } + } + + #endregion + + #region AddChargeContextMenuCommand Command + + /// + /// Private member backing variable for + /// + private RelayCommand _addChargeContextMenuCommand = null; + + /// + /// Comment + /// + public RelayCommand AddChargeContextMenuCommand => _addChargeContextMenuCommand ?? (_addChargeContextMenuCommand = new RelayCommand(AddChargeContextMenuCommand_Execute)); + + private void AddChargeContextMenuCommand_Execute() + { + var window = new AddTransactionView(TransactionType.Charge, PersonListViewSelectedItem); + window.ShowDialog(); + } + + #endregion + #region AddDepositContextMenuCommand Command + + /// + /// Private member backing variable for + /// + private RelayCommand _addDepositContextMenuCommand = null; + + /// + /// Comment + /// + public RelayCommand AddDepositContextMenuCommand => _addDepositContextMenuCommand ?? (_addDepositContextMenuCommand = new RelayCommand(AddDepositContextMenuCommand_Execute)); + + private void AddDepositContextMenuCommand_Execute() + { + var window = new AddTransactionView(TransactionType.Deposit, PersonListViewSelectedItem); + window.ShowDialog(); + } + + #endregion + #region NewPersonContextMenuCommand Command + + /// + /// Private member backing variable for + /// + private RelayCommand _newPersonContextMenuCommand = null; + + /// + /// Comment + /// + public RelayCommand NewPersonContextMenuCommand => _newPersonContextMenuCommand ?? (_newPersonContextMenuCommand = new RelayCommand(NewPersonContextMenuCommand_Execute)); + + private void NewPersonContextMenuCommand_Execute() + { + var window = new NewPersonDialogView(); + window.ShowDialog(); + } + + #endregion + #region DeletePersonContextMenuCommand Command + + /// + /// Private member backing variable for + /// + private RelayCommand _deletePersonContextMenuCommand = null; + + /// + /// Comment + /// + public RelayCommand DeletePersonContextMenuCommand => _deletePersonContextMenuCommand ?? (_deletePersonContextMenuCommand = new RelayCommand(DeletePersonContextMenuCommand_Execute, DeletePersonContextMenuCommand_CanExecute)); + + private bool DeletePersonContextMenuCommand_CanExecute() + { + if (PersonListViewSelectedItem != null) + return true; + return false; + } + + private void DeletePersonContextMenuCommand_Execute() + { + if (PersonListViewSelectedItem == null) return; + + var result = MessageBox.Show( + string.Format( + "Are you sure to delete?\n\n{0} {1}", + PersonListViewSelectedItem.FirstName, + PersonListViewSelectedItem.LastName), + "Delete Person", + MessageBoxButton.YesNo, + MessageBoxImage.Question); + + if (result == MessageBoxResult.Yes) + { + App.Database.Delete(PersonListViewSelectedItem.Id); + UpdatePersonsList(); + } + } + + #endregion + + #region DeleteTransactionContextMenuCommand Command + + /// + /// Private member backing variable for + /// + private RelayCommand _deleteTransactionContextMenuCommand = null; + + /// + /// Comment + /// + public RelayCommand DeleteTransactionContextMenuCommand => _deleteTransactionContextMenuCommand ?? (_deleteTransactionContextMenuCommand = new RelayCommand(DeleteTransactionContextMenuCommand_Execute, DeleteTransactionContextMenuCommand_CanExecute)); + + private bool DeleteTransactionContextMenuCommand_CanExecute() + { + if (TransactionHistoryListViewSelectedItem != null) + return true; + return false; + } + + private void DeleteTransactionContextMenuCommand_Execute() + { + if (TransactionHistoryListViewSelectedItem == null) return; + + var result = MessageBox.Show( + string.Format( + "Are you sure to delete?\n\n{1} €\n{0}", + TransactionHistoryListViewSelectedItem.Description, + TransactionHistoryListViewSelectedItem.Amount), + "Delete Transaction", + MessageBoxButton.YesNo, + MessageBoxImage.Question); + + if (result == MessageBoxResult.Yes) + { + App.Database.Delete(TransactionHistoryListViewSelectedItem.Id); + UpdatePersonsList(); + } + } + + #endregion + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Initializes a new instance of the MainViewModel class. + /// + /// Andre Beging, 10.09.2017. + //////////////////////////////////////////////////////////////////////////////////////////////////// + public MainViewModel() + { + CheckDatabase(); + + UpdatePersonsList(); + UpdateDetailView(); + } + + #region UpdatePersonsList() + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Updates the persons list. + /// + /// Andre Beging, 08.09.2017. + //////////////////////////////////////////////////////////////////////////////////////////////////// + public void UpdatePersonsList() + { + // Remember selection + var rememberSelection = PersonListViewSelectedItem?.Id; + + var personList = App.Database.GetAllWithChildren(); + PersonListViewItemSource = personList; + + var overallBalance = personList.Sum(x => x.Total); + OverallBalanceLabel = overallBalance.ToString(); + + // Restore selection + if (rememberSelection != null && PersonListViewItemSource.Any(x => x.Id == rememberSelection)) + PersonListViewSelectedItem = PersonListViewItemSource.First(x => x.Id == rememberSelection); + + UpdateDetailView(); + } + + #endregion + #region UpdateDetailView() + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Updates the detail view. + /// + /// Andre Beging, 10.09.2017. + //////////////////////////////////////////////////////////////////////////////////////////////////// + private void UpdateDetailView() + { + if (PersonListViewSelectedItem == null) + { + DetailViewHeaderLabelContent = string.Empty; + DetailViewBalanceLabel = string.Empty; + TransactionHistoryListViewItemSource = null; + return; + }; + + DetailViewHeaderLabelContent = string.Format("{0} {1}", PersonListViewSelectedItem.FirstName, + PersonListViewSelectedItem.LastName); + DetailViewBalanceLabel = PersonListViewSelectedItem.Total.ToString(); + + TransactionHistoryListViewItemSource = PersonListViewSelectedItem.Transactions.OrderByDescending(x => x.Time).ToList(); + } + + #endregion + + #region CheckDatabase() + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Check database. + /// + /// Andre Beging, 10.09.2017. + //////////////////////////////////////////////////////////////////////////////////////////////////// + private void CheckDatabase() + { + var databasePath = Properties.Settings.Default.Database; + if (string.IsNullOrWhiteSpace(databasePath)) + { + var window = new DatabaseSelectorDialogView(); + var result = window.ShowDialog(); + } + + // Check if provided file path is a valid database + try + { + App.Database.Table(); + } + catch (Exception) + { + Properties.Settings.Default["Database"] = string.Empty; + CheckDatabase(); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/ViewModel/ViewModelLocator.cs b/ViewModel/ViewModelLocator.cs new file mode 100644 index 0000000..8b465f6 --- /dev/null +++ b/ViewModel/ViewModelLocator.cs @@ -0,0 +1,61 @@ +/* + In App.xaml: + + + + + In the View: + DataContext="{Binding Source={StaticResource Locator}, Path=ViewModelName}" + + You can also use Blend to do all this with the tool's support. + See http://www.galasoft.ch/mvvm +*/ + +using DebtMgr.ViewModel.Dialogs; +using GalaSoft.MvvmLight.Ioc; +using Microsoft.Practices.ServiceLocation; + +namespace DebtMgr.ViewModel +{ + /// + /// This class contains static references to all the view models in the + /// application and provides an entry point for the bindings. + /// + public class ViewModelLocator + { + /// + /// Initializes a new instance of the ViewModelLocator class. + /// + public ViewModelLocator() + { + ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); + + ////if (ViewModelBase.IsInDesignModeStatic) + ////{ + //// // Create design time view services and models + //// SimpleIoc.Default.Register(); + ////} + ////else + ////{ + //// // Create run time view services and models + //// SimpleIoc.Default.Register(); + ////} + + SimpleIoc.Default.Register(); + SimpleIoc.Default.Register(); + SimpleIoc.Default.Register(); + SimpleIoc.Default.Register(); + } + + public MainViewModel MainView => ServiceLocator.Current.GetInstance(); + public NewPersonDialogViewModel NewPersonDialogView => ServiceLocator.Current.GetInstance(); + public AddTransactionViewModel AddTransactionView => ServiceLocator.Current.GetInstance(); + public DatabaseSelectorDialogViewModel DatabaseSelectorDialogView => ServiceLocator.Current.GetInstance(); + + public static void Cleanup() + { + // TODO Clear the ViewModels + } + } +} \ No newline at end of file diff --git a/packages.config b/packages.config new file mode 100644 index 0000000..bec897d --- /dev/null +++ b/packages.config @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/sqlite3.dll b/sqlite3.dll new file mode 100644 index 0000000..91185fe Binary files /dev/null and b/sqlite3.dll differ