diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..281b1c1 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,50 @@ +pipeline { + agent { label 'Kapitan-PC' } + environment { + ANDROID_HOME = 'C:\\Users\\lemi4\\AppData\\Local\\Android\\sdk' + DOTNET_ROOT = 'C:\\Program Files\\dotnet' + PATH = "${env.PATH};${env.ANDROID_HOME}\\tools;${env.ANDROID_HOME}\\platform-tools;${env.DOTNET_ROOT}" + } + stages { + stage('Checkout') { + steps { + checkout scm + } + } + stage('Restore Dependencies') { + steps { + script { + bat 'dotnet restore WheresMyMoney.sln' + } + } + } + stage('Build Android') { + steps { + script { + bat 'dotnet build WheresMyMoney.Maui\\WheresMyMoney.Maui.csproj -c Release -f net9.0-android' + } + } + } + stage('Build Windows') { + steps { + script { + bat 'dotnet build WheresMyMoney.Maui\\WheresMyMoney.Maui.csproj -c Release -f net9.0-windows10.0.19041.0' + } + } + } + stage('Publish Artifacts') { + steps { + script { + bat 'dotnet publish WheresMyMoney.Maui\\WheresMyMoney.Maui.csproj -c Release -f net9.0-android -o output\\android' + bat 'dotnet publish WheresMyMoney.Maui\\WheresMyMoney.Maui.csproj -c Release -f net9.0-windows10.0.19041.0 -o output\\windows' + } + archiveArtifacts artifacts: 'output/**/*', allowEmptyArchive: true + } + } + } + post { + always { + cleanWs() + } + } +} diff --git a/WheresMyMoney.Maui.Core/Repository.cs b/WheresMyMoney.Maui.Core/Repository.cs index 3edaeec..339ec48 100644 --- a/WheresMyMoney.Maui.Core/Repository.cs +++ b/WheresMyMoney.Maui.Core/Repository.cs @@ -81,7 +81,40 @@ public class Repository reoccurenceType is null ? DBNull.Value : (int)reoccurenceType.Value); command.ExecuteNonQuery(); - + + DataChanged(this, EventArgs.Empty); + } + + public void UpdatePlannedPayment(PlannedPayment plannedPayment) + { + using var command = _connection.CreateCommand(); + command.CommandText = """ + UPDATE planned_payment + SET amount = @amount, + name = @name, + date_start = @date_start, + date_end = @date_end, + is_subscription = @is_subscription, + reoccurences = @reoccurences, + reoccurence_type = @reoccurence_type + WHERE + id = @id; + """; + + command.Parameters.AddWithValue("@id", plannedPayment.Id); + command.Parameters.AddWithValue("@amount", (int)(plannedPayment.Amount * 100)); + command.Parameters.AddWithValue("@name", plannedPayment.Name); + command.Parameters.AddWithValue("@date_start", plannedPayment.DateStart); + command.Parameters.AddWithValue("@date_end", + plannedPayment.DateEnd.HasValue ? plannedPayment.DateEnd.Value : DBNull.Value); + command.Parameters.AddWithValue("@is_subscription", plannedPayment.IsSubscription); + command.Parameters.AddWithValue("@reoccurences", + plannedPayment.Reoccurences is null ? DBNull.Value : plannedPayment.Reoccurences.Value); + command.Parameters.AddWithValue("@reoccurence_type", + plannedPayment.ReoccurenceType is null ? DBNull.Value : (int)plannedPayment.ReoccurenceType.Value); + + command.ExecuteNonQuery(); + DataChanged(this, EventArgs.Empty); } @@ -97,7 +130,7 @@ public class Repository command.Parameters.AddWithValue("@date", date); command.ExecuteNonQuery(); - + DataChanged(this, EventArgs.Empty); } @@ -149,7 +182,7 @@ public class Repository command.Parameters.AddWithValue("@payday", newPayday); command.ExecuteNonQuery(); - + DataChanged(this, EventArgs.Empty); } @@ -248,6 +281,32 @@ public class Repository command.ExecuteNonQuery(); DataChanged(this, EventArgs.Empty); } - + public event EventHandler DataChanged; + + public PlannedPayment? GetPlannedPayment(int id) + { + using var command = _connection.CreateCommand(); + command.CommandText = """ + SELECT id, amount, name, date_start, date_end, is_subscription, reoccurences, reoccurence_type + FROM planned_payment + WHERE id = @id + """; + command.Parameters.AddWithValue("@id", id); + + using var reader = command.ExecuteReader(); + if (reader.Read()) + { + return new PlannedPayment(reader.GetInt32(0), + reader.GetDecimal(1) / 100m, + reader.GetString(2), + reader.GetDateTime(3), + reader.IsDBNull(4) ? null : reader.GetDateTime(4), + reader.GetBoolean(5), + reader.IsDBNull(6) ? null : reader.GetInt32(6), + reader.IsDBNull(7) ? null : (ReoccurenceType)reader.GetInt32(7)); + } + + return null; + } } \ No newline at end of file diff --git a/WheresMyMoney.Maui.Core/WheresMyMoney.Maui.Core.csproj b/WheresMyMoney.Maui.Core/WheresMyMoney.Maui.Core.csproj index a0d02f4..f995822 100644 --- a/WheresMyMoney.Maui.Core/WheresMyMoney.Maui.Core.csproj +++ b/WheresMyMoney.Maui.Core/WheresMyMoney.Maui.Core.csproj @@ -20,7 +20,7 @@ - + diff --git a/WheresMyMoney.Maui/AddPlannedPaymentPage.xaml.cs b/WheresMyMoney.Maui/AddPlannedPaymentPage.xaml.cs index 27052a6..27f911a 100644 --- a/WheresMyMoney.Maui/AddPlannedPaymentPage.xaml.cs +++ b/WheresMyMoney.Maui/AddPlannedPaymentPage.xaml.cs @@ -1,4 +1,4 @@ -using System.Diagnostics; +using System.Globalization; using WheresMyMoney.Maui.Core; namespace WheresMyMoney.Maui; @@ -13,7 +13,8 @@ public partial class AddPlannedPaymentPage : ContentPage private async void Add_OnClicked(object? sender, EventArgs e) { - if (!decimal.TryParse(AmountEntry.Text, out decimal amount)) return; + if (!decimal.TryParse(AmountEntry.Text, NumberStyles.Currency, CultureInfo.CurrentCulture, + out var amount)) return; var isSubscription = SubscriptionSwitch.IsToggled; var every = -1; var reoccurenceType = (ReoccurenceType)RepeatPicker.SelectedIndex; @@ -44,6 +45,6 @@ public partial class AddPlannedPaymentPage : ContentPage private void EveryEntry_OnCompleted(object? sender, EventArgs e) { - AmountEntry.Focus(); + this.AmountEntry.Focus(); } } \ No newline at end of file diff --git a/WheresMyMoney.Maui/AppShell.xaml b/WheresMyMoney.Maui/AppShell.xaml index 2bf5924..10803ca 100644 --- a/WheresMyMoney.Maui/AppShell.xaml +++ b/WheresMyMoney.Maui/AppShell.xaml @@ -9,18 +9,19 @@ Title="WheresMyMoney.Maui"> - - + - - + + - - + diff --git a/WheresMyMoney.Maui/AppShell.xaml.cs b/WheresMyMoney.Maui/AppShell.xaml.cs index 5ed7f14..5766845 100644 --- a/WheresMyMoney.Maui/AppShell.xaml.cs +++ b/WheresMyMoney.Maui/AppShell.xaml.cs @@ -5,5 +5,12 @@ public partial class AppShell : Shell public AppShell() { InitializeComponent(); +#if ANDROID || IOS + PlannedPaymentsShellContent.ContentTemplate = new DataTemplate(typeof(MobilePlannedPaymentsPage)); + PlannedPaymentsShellContent.Route = "MobilePlannedPaymentsPage"; +#else + PlannedPaymentsShellContent.ContentTemplate = new DataTemplate(typeof(PlannedPaymentsPage)); + PlannedPaymentsShellContent.Route = "PlannedPaymentsPage"; +#endif } } \ No newline at end of file diff --git a/WheresMyMoney.Maui/BalanceHistoryPage.xaml b/WheresMyMoney.Maui/BalanceHistoryPage.xaml index 2801d03..49380e7 100644 --- a/WheresMyMoney.Maui/BalanceHistoryPage.xaml +++ b/WheresMyMoney.Maui/BalanceHistoryPage.xaml @@ -6,7 +6,8 @@ x:Class="WheresMyMoney.Maui.BalanceHistoryPage"> + RemainingItemsThresholdReached="ItemsView_OnRemainingItemsThresholdReached" + x:DataType="local:BalanceHistoryPage"> @@ -23,7 +24,7 @@ + BindableLayout.ItemsSource="{Binding BalanceChanges}"> diff --git a/WheresMyMoney.Maui/BalancePage.xaml b/WheresMyMoney.Maui/BalancePage.xaml index c70c53f..a713ca1 100644 --- a/WheresMyMoney.Maui/BalancePage.xaml +++ b/WheresMyMoney.Maui/BalancePage.xaml @@ -51,7 +51,7 @@ - + diff --git a/WheresMyMoney.Maui/FullPlannedPaymentViewModel.cs b/WheresMyMoney.Maui/FullPlannedPaymentViewModel.cs index 338e6ce..56425f5 100644 --- a/WheresMyMoney.Maui/FullPlannedPaymentViewModel.cs +++ b/WheresMyMoney.Maui/FullPlannedPaymentViewModel.cs @@ -1,4 +1,6 @@ -namespace WheresMyMoney.Maui; +using System.Windows.Input; + +namespace WheresMyMoney.Maui; public record FullPlannedPaymentViewModel( int Id, @@ -9,4 +11,5 @@ public record FullPlannedPaymentViewModel( bool ShowDateEnd, bool IsSubscription, int? Reoccurences, - string? ReoccurenceType); \ No newline at end of file + string? ReoccurenceType, + ICommand? LongPressCommand); \ No newline at end of file diff --git a/WheresMyMoney.Maui/MauiProgram.cs b/WheresMyMoney.Maui/MauiProgram.cs index 330ffbf..41955dd 100644 --- a/WheresMyMoney.Maui/MauiProgram.cs +++ b/WheresMyMoney.Maui/MauiProgram.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.Logging; +using CommunityToolkit.Maui; +using Microsoft.Extensions.Logging; namespace WheresMyMoney.Maui; @@ -9,6 +10,8 @@ public static class MauiProgram var builder = MauiApp.CreateBuilder(); builder .UseMauiApp() + // Initialize the .NET MAUI Community Toolkit by adding the below line of code + .UseMauiCommunityToolkit() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); diff --git a/WheresMyMoney.Maui/MobilePlannedPaymentsPage.xaml b/WheresMyMoney.Maui/MobilePlannedPaymentsPage.xaml new file mode 100644 index 0000000..6ae97c1 --- /dev/null +++ b/WheresMyMoney.Maui/MobilePlannedPaymentsPage.xaml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WheresMyMoney.Maui/MobilePlannedPaymentsPage.xaml.cs b/WheresMyMoney.Maui/MobilePlannedPaymentsPage.xaml.cs new file mode 100644 index 0000000..8c4b564 --- /dev/null +++ b/WheresMyMoney.Maui/MobilePlannedPaymentsPage.xaml.cs @@ -0,0 +1,98 @@ +using System.Collections.ObjectModel; +using CommunityToolkit.Maui.Views; +using WheresMyMoney.Maui.Core; + +namespace WheresMyMoney.Maui; + +public partial class MobilePlannedPaymentsPage : ContentPage +{ + public ObservableCollection FullPlannedPaymentViewModels { get; } = []; + + public MobilePlannedPaymentsPage() + { + InitializeComponent(); + BindingContext = this; + UpdateUi(); + Repository.Instance.DataChanged += OnDataChanged; + } + + private void OnDataChanged(object? sender, EventArgs e) + { + UpdateUi(); + } + + private void UpdateUi() + { + FullPlannedPaymentViewModels.Clear(); + foreach (var plannedPayment in Repository.Instance.GetAllPlannedPayments()) + { + FullPlannedPaymentViewModels.Add(new FullPlannedPaymentViewModel(plannedPayment.Id, + plannedPayment.Amount.ToString("C"), plannedPayment.Name, + plannedPayment.DateStart.ToString("yyyy-MM-dd"), + plannedPayment.DateEnd?.ToString("yyyy-MM-dd") ?? string.Empty, plannedPayment.DateEnd is not null, + plannedPayment.IsSubscription, + plannedPayment.Reoccurences, + ReoccurenceTypeToString(plannedPayment.Reoccurences, plannedPayment.ReoccurenceType), + new Command(async () => + { + var popup = new PlannedPlannedPopup(); + var result = await this.ShowPopupAsync(popup, CancellationToken.None); + if (result is not PlannedPlannedPopup.PlannedPaymentPopupChoice choice) return; + switch (choice) + { + case PlannedPlannedPopup.PlannedPaymentPopupChoice.Modify: + await Navigation.PushModalAsync(new ModifyPlannedPaymentPage(plannedPayment.Id)); + break; + case PlannedPlannedPopup.PlannedPaymentPopupChoice.Remove: + await RemovePlannedPayment(plannedPayment.Id); + break; + default: + return; + } + }))); + } + } + + private static string ReoccurenceTypeToString(int? plannedPaymentReoccurences, + ReoccurenceType? plannedPaymentReoccurenceType) => + plannedPaymentReoccurenceType switch + { + ReoccurenceType.Days => plannedPaymentReoccurences switch + { + 1 => "dzień", + _ => "dni" + }, + ReoccurenceType.Weeks => (plannedPaymentReoccurences, plannedPaymentReoccurences % 10) switch + { + (1, _) => "tydzień", + (_, > 1 and < 5) => "tygodnie", + _ => "tygodni" + }, + ReoccurenceType.Months => (plannedPaymentReoccurences, plannedPaymentReoccurences % 10) switch + { + (1, _) => "miesiąc", + (_, > 1 and < 5) => "miesiące", + _ => "miesięcy" + }, + ReoccurenceType.Years => (plannedPaymentReoccurences, plannedPaymentReoccurences % 10) switch + { + (1, _) => "rok", + (_, > 1 and < 5) => "lata", + _ => "lat" + }, + ReoccurenceType.EveryLastDayOfMonth => "ostatni dzień miesiąca", + _ => string.Empty + }; + + private async void InsertPlannedPayment_OnClicked(object? sender, EventArgs e) + { + await Navigation.PushModalAsync(new AddPlannedPaymentPage()); + } + + private async Task RemovePlannedPayment(int id) + { + var answer = await DisplayAlert("Usunąć?", "Czy na pewno chcesz usunąć tą płatność?", "Tak", "Nie"); + if (!answer) return; + Repository.Instance.RemovePlannedPayment(id); + } +} \ No newline at end of file diff --git a/WheresMyMoney.Maui/ModifyPlannedPaymentPage.xaml b/WheresMyMoney.Maui/ModifyPlannedPaymentPage.xaml new file mode 100644 index 0000000..6fa717a --- /dev/null +++ b/WheresMyMoney.Maui/ModifyPlannedPaymentPage.xaml @@ -0,0 +1,76 @@ + + + + + +