Fixed bugs the following bugs:
* Opening the cost overview could lead to a crash if a cost entry did not cover all tenants. * The amount in the unit calculation window was not updated when changes were made. * After creation of a new billing the main window could be closed without getting a save dialog. Added autosave functionality.
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
# UCalc
|
||||||
|
|
||||||
|
UCalc oder MietRechner ist eine Anwendung zur Berechnung der Nebenkosten.
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Windows;
|
||||||
using UCalc.Data;
|
using UCalc.Data;
|
||||||
|
|
||||||
namespace UCalc
|
namespace UCalc
|
||||||
@@ -7,7 +8,9 @@ namespace UCalc
|
|||||||
public partial class App
|
public partial class App
|
||||||
{
|
{
|
||||||
private readonly RecentlyOpenedList _recentlyOpenedList;
|
private readonly RecentlyOpenedList _recentlyOpenedList;
|
||||||
|
private readonly Autosaver _autosaver;
|
||||||
public static RecentlyOpenedList RecentlyOpenedList => ((App) Current)._recentlyOpenedList;
|
public static RecentlyOpenedList RecentlyOpenedList => ((App) Current)._recentlyOpenedList;
|
||||||
|
public static Autosaver Autosaver => ((App) Current)._autosaver;
|
||||||
|
|
||||||
public App()
|
public App()
|
||||||
{
|
{
|
||||||
@@ -15,6 +18,14 @@ namespace UCalc
|
|||||||
Directory.CreateDirectory(appDataPath);
|
Directory.CreateDirectory(appDataPath);
|
||||||
|
|
||||||
_recentlyOpenedList = new RecentlyOpenedList($"{appDataPath}/recently.txt");
|
_recentlyOpenedList = new RecentlyOpenedList($"{appDataPath}/recently.txt");
|
||||||
|
_autosaver = new Autosaver($"{appDataPath}/running.txt", $"{appDataPath}/autosave.mr");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnExit(ExitEventArgs e)
|
||||||
|
{
|
||||||
|
_autosaver.OnExit();
|
||||||
|
|
||||||
|
base.OnExit(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
using UCalc.Data;
|
||||||
|
using UCalc.Models;
|
||||||
|
|
||||||
|
namespace UCalc
|
||||||
|
{
|
||||||
|
public class Autosaver
|
||||||
|
{
|
||||||
|
private readonly string _runningPath;
|
||||||
|
private SaverThread _saverThread;
|
||||||
|
public string AutosavePath { get; }
|
||||||
|
public bool CanRecover { get; private set; }
|
||||||
|
|
||||||
|
public Model OpenModel
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
CanRecover = false;
|
||||||
|
|
||||||
|
if (value != null)
|
||||||
|
{
|
||||||
|
_saverThread = new SaverThread(15, AutosavePath, value);
|
||||||
|
}
|
||||||
|
else if (_saverThread != null)
|
||||||
|
{
|
||||||
|
_saverThread.Terminate();
|
||||||
|
_saverThread = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Autosaver(string runningPath, string autosavePath)
|
||||||
|
{
|
||||||
|
_runningPath = runningPath;
|
||||||
|
AutosavePath = autosavePath;
|
||||||
|
|
||||||
|
CanRecover = File.Exists(runningPath) && File.Exists(autosavePath);
|
||||||
|
|
||||||
|
File.WriteAllText(runningPath, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnExit()
|
||||||
|
{
|
||||||
|
if (!CanRecover)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.Delete(_runningPath);
|
||||||
|
}
|
||||||
|
catch (IOException)
|
||||||
|
{
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SaverThread
|
||||||
|
{
|
||||||
|
private volatile bool _terminate;
|
||||||
|
private readonly int _saveIntervalInS;
|
||||||
|
private readonly string _autosavePath;
|
||||||
|
private readonly Model _model;
|
||||||
|
|
||||||
|
public SaverThread(int saveIntervalInS, string autosavePath, Model model)
|
||||||
|
{
|
||||||
|
_terminate = false;
|
||||||
|
_saveIntervalInS = saveIntervalInS;
|
||||||
|
_autosavePath = autosavePath;
|
||||||
|
_model = model;
|
||||||
|
|
||||||
|
new Thread(ThreadFunc).Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Terminate()
|
||||||
|
{
|
||||||
|
_terminate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThreadFunc()
|
||||||
|
{
|
||||||
|
var start = DateTime.Now;
|
||||||
|
|
||||||
|
while (!_terminate)
|
||||||
|
{
|
||||||
|
Thread.Sleep(500);
|
||||||
|
|
||||||
|
if ((DateTime.Now - start).Seconds >= _saveIntervalInS)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
BillingLoader.Store(_autosavePath, _model.Dump());
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
start = DateTime.Now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -47,7 +47,7 @@ namespace UCalc
|
|||||||
public BillingWindow(string filePath, Billing billing)
|
public BillingWindow(string filePath, Billing billing)
|
||||||
{
|
{
|
||||||
FilePath = filePath;
|
FilePath = filePath;
|
||||||
Model = new Model(billing);
|
Model = new Model(billing, filePath == null);
|
||||||
SaveCommand = new DelegateCommand(parameter => { Save(); });
|
SaveCommand = new DelegateCommand(parameter => { Save(); });
|
||||||
SaveAsCommand = new DelegateCommand(parameter => { Save(true); });
|
SaveAsCommand = new DelegateCommand(parameter => { Save(true); });
|
||||||
PrintCommand = new DelegateCommand(parameter => { Print(); });
|
PrintCommand = new DelegateCommand(parameter => { Print(); });
|
||||||
@@ -56,6 +56,8 @@ namespace UCalc
|
|||||||
|
|
||||||
Title =
|
Title =
|
||||||
$"MietRechner - Abrechnung von {billing.StartDate.ToString(Constants.DateFormat)} - {billing.EndDate.Date.ToString(Constants.DateFormat)}";
|
$"MietRechner - Abrechnung von {billing.StartDate.ToString(Constants.DateFormat)} - {billing.EndDate.Date.ToString(Constants.DateFormat)}";
|
||||||
|
|
||||||
|
App.Autosaver.OpenModel = Model;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnClosing(object sender, CancelEventArgs e)
|
private void OnClosing(object sender, CancelEventArgs e)
|
||||||
@@ -90,6 +92,8 @@ namespace UCalc
|
|||||||
|
|
||||||
private void OnClosed(object sender, EventArgs e)
|
private void OnClosed(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
App.Autosaver.OpenModel = null;
|
||||||
|
|
||||||
Application.Current.MainWindow?.Show();
|
Application.Current.MainWindow?.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,11 @@ namespace UCalc
|
|||||||
Details.UnitCount.PropertyChanged += DetailsPropertyChanged;
|
Details.UnitCount.PropertyChanged += DetailsPropertyChanged;
|
||||||
Details.DiscountsInUnits.CollectionChanged += DetailsDiscountChanged;
|
Details.DiscountsInUnits.CollectionChanged += DetailsDiscountChanged;
|
||||||
|
|
||||||
|
foreach (var discountInUnits in Details.DiscountsInUnits)
|
||||||
|
{
|
||||||
|
discountInUnits.PropertyChanged += DetailsPropertyChanged;
|
||||||
|
}
|
||||||
|
|
||||||
DetailsPropertyChanged(null, null);
|
DetailsPropertyChanged(null, null);
|
||||||
|
|
||||||
if (Details.TotalAmount.ConvertedValue != 0 || Details.UnitCount.ConvertedValue != 0 ||
|
if (Details.TotalAmount.ConvertedValue != 0 || Details.UnitCount.ConvertedValue != 0 ||
|
||||||
@@ -91,6 +96,8 @@ namespace UCalc
|
|||||||
discount.PropertyChanged -= DetailsPropertyChanged;
|
discount.PropertyChanged -= DetailsPropertyChanged;
|
||||||
discount.PropertyChanged += DetailsPropertyChanged;
|
discount.PropertyChanged += DetailsPropertyChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DetailsPropertyChanged(sender, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCEClick(object sender, RoutedEventArgs e)
|
private void OnCEClick(object sender, RoutedEventArgs e)
|
||||||
|
|||||||
@@ -663,9 +663,15 @@ namespace UCalc.Data
|
|||||||
new Tuple<decimal, decimal, decimal>(0, 0, 0),
|
new Tuple<decimal, decimal, decimal>(0, 0, 0),
|
||||||
(sum, tenantResult) =>
|
(sum, tenantResult) =>
|
||||||
{
|
{
|
||||||
var costResult = tenantResult.Costs[cost];
|
if (tenantResult.Costs.TryGetValue(cost, out var costResult))
|
||||||
|
{
|
||||||
return new Tuple<decimal, decimal, decimal>(sum.Item1 + costResult.TotalAmount,
|
return new Tuple<decimal, decimal, decimal>(sum.Item1 + costResult.TotalAmount,
|
||||||
sum.Item2 + costResult.PastAmount, sum.Item3 + costResult.FutureAmount);
|
sum.Item2 + costResult.PastAmount, sum.Item3 + costResult.FutureAmount);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
str.Append("Auf Mieter umgelegt:\n");
|
str.Append("Auf Mieter umgelegt:\n");
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.IO;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Controls.Primitives;
|
using System.Windows.Controls.Primitives;
|
||||||
@@ -10,9 +11,37 @@ namespace UCalc
|
|||||||
{
|
{
|
||||||
public partial class MainWindow
|
public partial class MainWindow
|
||||||
{
|
{
|
||||||
|
private bool _showRecover;
|
||||||
|
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
_showRecover = App.Autosaver.CanRecover;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnContentRendered(EventArgs e)
|
||||||
|
{
|
||||||
|
base.OnContentRendered(e);
|
||||||
|
|
||||||
|
if (_showRecover)
|
||||||
|
{
|
||||||
|
_showRecover = false;
|
||||||
|
|
||||||
|
switch (MessageBox.Show(
|
||||||
|
"Die Anwendung wurde das letzte Mal nicht richtig beendet. Es existiert allerdings eine Sicherheitskopie. Möchten Sie diese laden?",
|
||||||
|
"Sicherheitskopie laden?",
|
||||||
|
MessageBoxButton.YesNo, MessageBoxImage.Question))
|
||||||
|
{
|
||||||
|
case MessageBoxResult.Yes:
|
||||||
|
OpenBilling(App.Autosaver.AutosavePath, true);
|
||||||
|
break;
|
||||||
|
case MessageBoxResult.No:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnNewClick(object sender, RoutedEventArgs e)
|
private void OnNewClick(object sender, RoutedEventArgs e)
|
||||||
@@ -67,14 +96,17 @@ namespace UCalc
|
|||||||
OpenBilling(recentlyOpenedItem.Path);
|
OpenBilling(recentlyOpenedItem.Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OpenBilling(string path)
|
private void OpenBilling(string path, bool isRecovery = false)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var billing = BillingLoader.Load(path);
|
var billing = BillingLoader.Load(path);
|
||||||
|
if (!isRecovery)
|
||||||
|
{
|
||||||
App.RecentlyOpenedList.Add(new RecentlyOpenedItem(path));
|
App.RecentlyOpenedList.Add(new RecentlyOpenedItem(path));
|
||||||
|
}
|
||||||
|
|
||||||
new BillingWindow(path, billing).Show();
|
new BillingWindow(isRecovery ? null : path, billing).Show();
|
||||||
Hide();
|
Hide();
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
|
|||||||
@@ -161,12 +161,19 @@ namespace UCalc.Models
|
|||||||
private readonly Validator _validator;
|
private readonly Validator _validator;
|
||||||
public BillingProperty Root { get; }
|
public BillingProperty Root { get; }
|
||||||
|
|
||||||
public Model(Billing billing)
|
public Model(Billing billing, bool modified)
|
||||||
{
|
{
|
||||||
_validator = new Validator(this);
|
_validator = new Validator(this);
|
||||||
|
|
||||||
using var validator = BeginValidation(true);
|
using var validator = BeginValidation(true);
|
||||||
|
|
||||||
Root = new BillingProperty(billing.StartDate, billing.EndDate, this, null, billing);
|
Root = new BillingProperty(billing.StartDate, billing.EndDate, this, null, billing);
|
||||||
|
if (modified)
|
||||||
|
{
|
||||||
|
var oldName = Root.Landlord.Name.Value;
|
||||||
|
Root.Landlord.Name.Value = $"{oldName}_";
|
||||||
|
Root.Landlord.Name.Value = oldName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Validator BeginValidation(bool postPone = false)
|
public Validator BeginValidation(bool postPone = false)
|
||||||
|
|||||||
@@ -106,11 +106,12 @@ namespace UCalc.Models
|
|||||||
}
|
}
|
||||||
|
|
||||||
_value = value;
|
_value = value;
|
||||||
OnPropertyChanged();
|
|
||||||
|
|
||||||
using var validator = Model.BeginValidation();
|
using var validator = Model.BeginValidation();
|
||||||
Modified = true;
|
Modified = true;
|
||||||
validator.Validate(this);
|
validator.Validate(this);
|
||||||
|
|
||||||
|
OnPropertyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ namespace UCalc.Pages
|
|||||||
|
|
||||||
private void OnAboutClick(object sender, RoutedEventArgs e)
|
private void OnAboutClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
MessageBox.Show("MietRechner Version 2.0\n\nCopyright © 2020 by Tobias Erbshäußer", "Über MietRechner",
|
MessageBox.Show("MietRechner Version 2.1\n\nCopyright © 2020-2021 by Tobias Erbshäußer", "Über MietRechner",
|
||||||
MessageBoxButton.OK, MessageBoxImage.Information);
|
MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user