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.IO;
|
||||
using System.Windows;
|
||||
using UCalc.Data;
|
||||
|
||||
namespace UCalc
|
||||
@@ -7,7 +8,9 @@ namespace UCalc
|
||||
public partial class App
|
||||
{
|
||||
private readonly RecentlyOpenedList _recentlyOpenedList;
|
||||
private readonly Autosaver _autosaver;
|
||||
public static RecentlyOpenedList RecentlyOpenedList => ((App) Current)._recentlyOpenedList;
|
||||
public static Autosaver Autosaver => ((App) Current)._autosaver;
|
||||
|
||||
public App()
|
||||
{
|
||||
@@ -15,6 +18,14 @@ namespace UCalc
|
||||
Directory.CreateDirectory(appDataPath);
|
||||
|
||||
_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)
|
||||
{
|
||||
FilePath = filePath;
|
||||
Model = new Model(billing);
|
||||
Model = new Model(billing, filePath == null);
|
||||
SaveCommand = new DelegateCommand(parameter => { Save(); });
|
||||
SaveAsCommand = new DelegateCommand(parameter => { Save(true); });
|
||||
PrintCommand = new DelegateCommand(parameter => { Print(); });
|
||||
@@ -56,6 +56,8 @@ namespace UCalc
|
||||
|
||||
Title =
|
||||
$"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)
|
||||
@@ -90,6 +92,8 @@ namespace UCalc
|
||||
|
||||
private void OnClosed(object sender, EventArgs e)
|
||||
{
|
||||
App.Autosaver.OpenModel = null;
|
||||
|
||||
Application.Current.MainWindow?.Show();
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,11 @@ namespace UCalc
|
||||
Details.UnitCount.PropertyChanged += DetailsPropertyChanged;
|
||||
Details.DiscountsInUnits.CollectionChanged += DetailsDiscountChanged;
|
||||
|
||||
foreach (var discountInUnits in Details.DiscountsInUnits)
|
||||
{
|
||||
discountInUnits.PropertyChanged += DetailsPropertyChanged;
|
||||
}
|
||||
|
||||
DetailsPropertyChanged(null, null);
|
||||
|
||||
if (Details.TotalAmount.ConvertedValue != 0 || Details.UnitCount.ConvertedValue != 0 ||
|
||||
@@ -91,6 +96,8 @@ namespace UCalc
|
||||
discount.PropertyChanged -= DetailsPropertyChanged;
|
||||
discount.PropertyChanged += DetailsPropertyChanged;
|
||||
}
|
||||
|
||||
DetailsPropertyChanged(sender, null);
|
||||
}
|
||||
|
||||
private void OnCEClick(object sender, RoutedEventArgs e)
|
||||
|
||||
@@ -663,9 +663,15 @@ namespace UCalc.Data
|
||||
new Tuple<decimal, decimal, decimal>(0, 0, 0),
|
||||
(sum, tenantResult) =>
|
||||
{
|
||||
var costResult = tenantResult.Costs[cost];
|
||||
return new Tuple<decimal, decimal, decimal>(sum.Item1 + costResult.TotalAmount,
|
||||
sum.Item2 + costResult.PastAmount, sum.Item3 + costResult.FutureAmount);
|
||||
if (tenantResult.Costs.TryGetValue(cost, out var costResult))
|
||||
{
|
||||
return new Tuple<decimal, decimal, decimal>(sum.Item1 + costResult.TotalAmount,
|
||||
sum.Item2 + costResult.PastAmount, sum.Item3 + costResult.FutureAmount);
|
||||
}
|
||||
else
|
||||
{
|
||||
return sum;
|
||||
}
|
||||
});
|
||||
|
||||
str.Append("Auf Mieter umgelegt:\n");
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
@@ -10,9 +11,37 @@ namespace UCalc
|
||||
{
|
||||
public partial class MainWindow
|
||||
{
|
||||
private bool _showRecover;
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
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)
|
||||
@@ -67,14 +96,17 @@ namespace UCalc
|
||||
OpenBilling(recentlyOpenedItem.Path);
|
||||
}
|
||||
|
||||
private void OpenBilling(string path)
|
||||
private void OpenBilling(string path, bool isRecovery = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
var billing = BillingLoader.Load(path);
|
||||
App.RecentlyOpenedList.Add(new RecentlyOpenedItem(path));
|
||||
if (!isRecovery)
|
||||
{
|
||||
App.RecentlyOpenedList.Add(new RecentlyOpenedItem(path));
|
||||
}
|
||||
|
||||
new BillingWindow(path, billing).Show();
|
||||
new BillingWindow(isRecovery ? null : path, billing).Show();
|
||||
Hide();
|
||||
}
|
||||
catch (IOException e)
|
||||
|
||||
@@ -161,12 +161,19 @@ namespace UCalc.Models
|
||||
private readonly Validator _validator;
|
||||
public BillingProperty Root { get; }
|
||||
|
||||
public Model(Billing billing)
|
||||
public Model(Billing billing, bool modified)
|
||||
{
|
||||
_validator = new Validator(this);
|
||||
|
||||
using var validator = BeginValidation(true);
|
||||
|
||||
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)
|
||||
|
||||
@@ -106,11 +106,12 @@ namespace UCalc.Models
|
||||
}
|
||||
|
||||
_value = value;
|
||||
OnPropertyChanged();
|
||||
|
||||
using var validator = Model.BeginValidation();
|
||||
Modified = true;
|
||||
validator.Validate(this);
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace UCalc.Pages
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user