377 lines
14 KiB
C#
377 lines
14 KiB
C#
using BlueMine.Redmine;
|
|
using System.Collections.ObjectModel;
|
|
using System.Diagnostics;
|
|
using System.Text.RegularExpressions;
|
|
using System.Windows;
|
|
using System.Windows.Input;
|
|
using Wpf.Ui.Controls;
|
|
using static BlueMine.Redmine.RedmineDto;
|
|
|
|
namespace BlueMine
|
|
{
|
|
/// <summary>
|
|
/// Interaction logic for MainWindow.xaml
|
|
/// </summary>
|
|
public partial class MainWindow : FluentWindow
|
|
{
|
|
private readonly RedmineManager _manager;
|
|
private readonly SettingsManager _settings;
|
|
private readonly RedmineConfig _config;
|
|
private List<IssueItem> _issues = [];
|
|
public ObservableCollection<IssueItem> IssuesList { get; set; } = [];
|
|
|
|
public MainWindow(RedmineManager manager, SettingsManager settings, RedmineConfig config)
|
|
{
|
|
_settings = settings;
|
|
_config = config;
|
|
_manager = manager;
|
|
InitializeComponent();
|
|
DataContext = this;
|
|
}
|
|
|
|
private async void WindowLoaded(object sender, RoutedEventArgs e)
|
|
{
|
|
apiUrlTextBox.Text = _config.RedmineUrl;
|
|
apiPasswordBox.PlaceholderText = new string('●', _config.ApiKey.Length);
|
|
|
|
if(await TestConnection())
|
|
{
|
|
await LoadIssues();
|
|
await GetHours();
|
|
}
|
|
}
|
|
|
|
private void CalendarButtonClicked(object sender, RoutedEventArgs e)
|
|
{
|
|
flyoutCalendar.IsOpen = true;
|
|
}
|
|
|
|
private IProgress<(int, int)> UpdateProgress(string message)
|
|
{
|
|
var progress = new Progress<(int current, int total)>();
|
|
progress.ProgressChanged += (s, args) =>
|
|
{
|
|
int current = args.current;
|
|
int total = args.total;
|
|
statusTextBlock.Text = $"{message}: {current} / {total}";
|
|
progressBar.Value = (double)current / total * 100;
|
|
};
|
|
return progress;
|
|
}
|
|
|
|
private void ApiButtonClicked(object sender, RoutedEventArgs e)
|
|
{
|
|
apiFlyout.IsOpen = true;
|
|
}
|
|
|
|
private void CalendarSelectedDatesChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
|
{
|
|
if(mainCalendar.SelectedDates.Count == 1)
|
|
calendarButton.Content = mainCalendar.SelectedDate?.ToString("yyyy-MM-dd");
|
|
else if(mainCalendar.SelectedDates.Count > 1)
|
|
calendarButton.Content = $"{mainCalendar.SelectedDates.Count} nap kiválasztva";
|
|
else
|
|
calendarButton.Content = "Válassz egy napot";
|
|
}
|
|
|
|
private void apiLinkButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
string url = "https://support.onliveit.eu:444/redmine/my/account";
|
|
|
|
var psi = new ProcessStartInfo
|
|
{
|
|
FileName = url,
|
|
UseShellExecute = true
|
|
};
|
|
Process.Start(psi);
|
|
}
|
|
|
|
private async void apiSaveButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
_config.RedmineUrl = apiUrlTextBox.Text;
|
|
_config.ApiKey = apiPasswordBox.Password;
|
|
apiFlyout.IsOpen = false;
|
|
if(await TestConnection())
|
|
{
|
|
_settings.Save(_config);
|
|
statusTextBlock.Text = "Beállítások mentve és kapcsolódva";
|
|
await LoadIssues();
|
|
await GetHours();
|
|
}
|
|
else
|
|
{
|
|
_settings.Save(_config);
|
|
statusTextBlock.Text = "Beállítások mentve, de a Redmine nem elérhető";
|
|
}
|
|
}
|
|
|
|
private void DataGridSelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
|
{
|
|
/*if (issuesDataGrid.SelectedItem is IssueItem item)
|
|
{
|
|
IssueNumberTextBox.Text = item.IssueNumber.ToString();
|
|
}*/
|
|
|
|
}
|
|
|
|
private void SearchTextBoxTextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
|
|
{
|
|
FilterIssues();
|
|
}
|
|
|
|
private async void RefreshButtonClick(object sender, RoutedEventArgs e)
|
|
{
|
|
await LoadIssues();
|
|
await GetHours();
|
|
}
|
|
|
|
private void BrowserButtonClick(object sender, RoutedEventArgs e)
|
|
{
|
|
var issueNum = IssueNumberTextBox.Text;
|
|
if (int.TryParse(issueNum, out var issueId))
|
|
{
|
|
string url = $"https://support.onliveit.eu:444/redmine/issues/{issueId}";
|
|
|
|
var psi = new ProcessStartInfo
|
|
{
|
|
FileName = url,
|
|
UseShellExecute = true
|
|
};
|
|
Process.Start(psi);
|
|
}
|
|
}
|
|
|
|
private async void CloseButtonClick(object sender, RoutedEventArgs e)
|
|
{
|
|
var issueNum = IssueNumberTextBox.Text;
|
|
if (int.TryParse(issueNum, out var issueId))
|
|
{
|
|
try
|
|
{
|
|
await _manager.CloseIssueAsync(issueId);
|
|
await new Wpf.Ui.Controls.MessageBox
|
|
{
|
|
Title = "Sikeres művelet",
|
|
Content = $"A(z) {issueId} számú jegy lezárva.",
|
|
}.ShowDialogAsync();
|
|
}
|
|
catch (Exception)
|
|
{
|
|
await new Wpf.Ui.Controls.MessageBox
|
|
{
|
|
Title = "Hiba",
|
|
Content = $"A(z) {issueId} számú jegy lezárása sikertelen.",
|
|
}.ShowDialogAsync();
|
|
}
|
|
}
|
|
|
|
await new Wpf.Ui.Controls.MessageBox
|
|
{
|
|
Title = "Hiba",
|
|
Content = "Érvénytelen jegyszám.",
|
|
}.ShowDialogAsync();
|
|
}
|
|
|
|
private async void FixButtonClick(object sender, RoutedEventArgs e)
|
|
{
|
|
var progress = UpdateProgress("Idők javítása:");
|
|
|
|
var i = 0;
|
|
foreach (var date in mainCalendar.SelectedDates)
|
|
{
|
|
var hours = 8 - await _manager.GetLoggedHoursAsync(date, date);
|
|
if (hours <= 0)
|
|
continue;
|
|
var message = Constants.GenericMessages[Random.Shared.Next(Constants.GenericMessages.Length)];
|
|
var id = 801;
|
|
await _manager.LogTimeAsync(id, hours, message, date);
|
|
progress.Report((i, mainCalendar.SelectedDates.Count));
|
|
i++;
|
|
}
|
|
progressBar.Value = 0;
|
|
await GetHours();
|
|
statusTextBlock.Text = "Idők javítva";
|
|
|
|
}
|
|
|
|
private async void sendButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
if(int.TryParse(IssueNumberTextBox.Text, out var issueId)
|
|
&& double.TryParse(HoursTextBox.Text, out var hours))
|
|
{
|
|
if (hours * 4 != Math.Floor(hours * 4))
|
|
{
|
|
await new Wpf.Ui.Controls.MessageBox
|
|
{
|
|
Title = "Idő formátum hiba",
|
|
Content = "Az idő csak negyedórákra bontható le."
|
|
}.ShowDialogAsync();
|
|
return;
|
|
}
|
|
var total = mainCalendar.SelectedDates.Count;
|
|
var progress = UpdateProgress("Idők beköldése:");
|
|
for (int i = 0; i < total; i++)
|
|
{
|
|
await _manager.LogTimeAsync(issueId, hours, MessageTextBox.Text, mainCalendar.SelectedDates[i]);
|
|
progress.Report((i, total));
|
|
}
|
|
progressBar.Value = 0;
|
|
statusTextBlock.Text = "Idők beküldve";
|
|
|
|
await GetHours();
|
|
} else
|
|
{
|
|
await new Wpf.Ui.Controls.MessageBox
|
|
{
|
|
Title = "Szám formátum hiba",
|
|
Content = "Az idő/jegyszám nem rendes szám."
|
|
}.ShowDialogAsync();
|
|
return;
|
|
}
|
|
}
|
|
|
|
private void ListView_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
|
{
|
|
var lv = sender as ListView;
|
|
if(lv != null && lv.SelectedItem is IssueItem item)
|
|
{
|
|
IssueNumberTextBox.Text = item.IssueNumber.ToString();
|
|
}
|
|
}
|
|
}
|
|
|
|
public partial class MainWindow : FluentWindow
|
|
{
|
|
private static readonly Regex _regexFractions = new Regex(@"^[0-9]*(?:\.[0-9]*)?$");
|
|
private static readonly Regex _regexNumbers = new Regex(@"^[0-9]*$");
|
|
private void FracValidation(object sender, TextCompositionEventArgs e)
|
|
{
|
|
var textBox = sender as TextBox;
|
|
// Construct what the text WILL be if we allow this input
|
|
string fullText = HoursTextBox.Text.Insert(HoursTextBox.CaretIndex, e.Text);
|
|
|
|
// If the resulting text is not a match, block the input
|
|
e.Handled = !_regexFractions.IsMatch(fullText);
|
|
}
|
|
private void FracPasting(object sender, DataObjectPastingEventArgs e)
|
|
{
|
|
if (e.DataObject.GetDataPresent(typeof(string)))
|
|
{
|
|
string text = (string)e.DataObject.GetData(typeof(string));
|
|
var textBox = sender as TextBox;
|
|
string fullText = HoursTextBox.Text.Insert(HoursTextBox.CaretIndex, text);
|
|
|
|
if (!_regexFractions.IsMatch(fullText))
|
|
e.CancelCommand();
|
|
|
|
}
|
|
else
|
|
e.CancelCommand();
|
|
}
|
|
private void NumValidation(object sender, TextCompositionEventArgs e)
|
|
{
|
|
var textBox = sender as TextBox;
|
|
// Construct what the text WILL be if we allow this input
|
|
string fullText = HoursTextBox.Text.Insert(HoursTextBox.CaretIndex, e.Text);
|
|
|
|
// If the resulting text is not a match, block the input
|
|
e.Handled = !_regexNumbers.IsMatch(fullText);
|
|
}
|
|
private void NumPasting(object sender, DataObjectPastingEventArgs e)
|
|
{
|
|
if (e.DataObject.GetDataPresent(typeof(string)))
|
|
{
|
|
string text = (string)e.DataObject.GetData(typeof(string));
|
|
var textBox = sender as TextBox;
|
|
string fullText = HoursTextBox.Text.Insert(HoursTextBox.CaretIndex, text);
|
|
|
|
if (!_regexNumbers.IsMatch(fullText))
|
|
e.CancelCommand();
|
|
|
|
}
|
|
else
|
|
e.CancelCommand();
|
|
}
|
|
|
|
public async Task GetHours()
|
|
{
|
|
var today = await _manager.GetLoggedHoursAsync(DateTime.Today, DateTime.Today);
|
|
var yesterday = await _manager.GetLoggedHoursAsync(DateTime.Today.AddDays(-1), DateTime.Today.AddDays(-1));
|
|
|
|
var m = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1);
|
|
var thisMonth = await _manager.GetLoggedHoursAsync(m, m.AddMonths(1).AddDays(-1));
|
|
|
|
todayTimeLabel.Text = today.ToString();
|
|
yesterdayTimeLabel.Text = yesterday.ToString();
|
|
monthTimeLabel.Text = thisMonth.ToString();
|
|
}
|
|
public void FilterIssues()
|
|
{
|
|
var list = string.IsNullOrWhiteSpace(searchTextBox.Text)
|
|
? _issues
|
|
: _issues.Where(issue => issue.IssueName.Contains(searchTextBox.Text, StringComparison.OrdinalIgnoreCase)
|
|
|| issue.IssueNumber.ToString().Contains(searchTextBox.Text)
|
|
|| issue.ProjectName.Contains(searchTextBox.Text, StringComparison.OrdinalIgnoreCase));
|
|
IssuesList.Clear();
|
|
foreach (var item in list)
|
|
{
|
|
IssuesList.Add(item);
|
|
}
|
|
}
|
|
public async Task LoadIssues()
|
|
{
|
|
_issues.Clear();
|
|
_issues.AddRange(Constants.StaticTickets);
|
|
_issues.AddRange(await _manager.GetCurrentIssuesAsync(UpdateProgress("Jegyek letöltése:")));
|
|
progressBar.Value = 0;
|
|
FilterIssues();
|
|
statusTextBlock.Text = "Jegyek letöltve";
|
|
}
|
|
public void DisableUi()
|
|
{
|
|
searchTextBox.IsEnabled =
|
|
//issuesDataGrid.IsEnabled =
|
|
IssueNumberTextBox.IsEnabled =
|
|
HoursTextBox.IsEnabled =
|
|
MessageTextBox.IsEnabled =
|
|
calendarButton.IsEnabled =
|
|
sendButton.IsEnabled =
|
|
closeButton.IsEnabled =
|
|
browserButton.IsEnabled =
|
|
newButton.IsEnabled =
|
|
refreshButton.IsEnabled =
|
|
fixButton.IsEnabled = false;
|
|
}
|
|
public void EnableUi()
|
|
{
|
|
searchTextBox.IsEnabled =
|
|
//issuesDataGrid.IsEnabled =
|
|
IssueNumberTextBox.IsEnabled =
|
|
HoursTextBox.IsEnabled =
|
|
MessageTextBox.IsEnabled =
|
|
calendarButton.IsEnabled =
|
|
sendButton.IsEnabled =
|
|
closeButton.IsEnabled =
|
|
browserButton.IsEnabled =
|
|
newButton.IsEnabled =
|
|
refreshButton.IsEnabled =
|
|
fixButton.IsEnabled = true;
|
|
}
|
|
public async Task<bool> TestConnection()
|
|
{
|
|
if (!await _manager.IsRedmineAvailable())
|
|
{
|
|
DisableUi();
|
|
apiButton.Appearance = Wpf.Ui.Controls.ControlAppearance.Primary;
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
EnableUi();
|
|
apiButton.Appearance = Wpf.Ui.Controls.ControlAppearance.Secondary;
|
|
statusTextBlock.Text = "Kapcsolódva";
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
} |