Skip to content

Commit 17843c8

Browse files
authored
Merge pull request #15 from EnesEfeTokta/Develop
Develop
2 parents 925abb8 + 4a09817 commit 17843c8

27 files changed

+1461
-319
lines changed

FinTrack/App.xaml.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using FinTrackForWindows.Services.Accounts;
55
using FinTrackForWindows.Services.Api;
66
using FinTrackForWindows.Services.Budgets;
7+
using FinTrackForWindows.Services.Camera;
78
using FinTrackForWindows.Services.Currencies;
89
using FinTrackForWindows.Services.Debts;
910
using FinTrackForWindows.Services.Memberships;
@@ -87,6 +88,8 @@ private void ConfigureServices(IServiceCollection services)
8788
services.AddSingleton<ICurrenciesStore, CurrenciesStore>();
8889
services.AddSingleton<IMembershipStore, MembershipStore>();
8990
services.AddSingleton<IDebtStore, DebtStore>();
91+
92+
services.AddTransient<ICameraService, CameraService>();
9093
}
9194

9295
protected override async void OnStartup(StartupEventArgs e)

FinTrack/Dtos/DebtDtos/DebtDto.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public class DebtDto
1818
public DateTime DueDateUtc { get; set; }
1919
public string Description { get; set; } = null!;
2020
public DebtStatusType Status { get; set; }
21+
public int? VideoMetadataId { get; set; }
2122
public DateTime CreateAtUtc { get; set; }
2223
public DateTime? UpdatedAtUtc { get; set; }
2324
public DateTime? PaidAtUtc { get; set; }

FinTrack/Enums/DebtStatus.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
public enum DebtStatusType
44
{
55
PendingBorrowerAcceptance, // Borç Alan Onayı Bekliyor
6-
AcceptedPendingVideoUpload, // Borçlu Kabul Etti, Video Yüklemesi Bekleniyor (YENİ)
6+
AcceptedPendingVideoUpload, // Borçlu Kabul Etti, Video Yüklemesi Bekleniyor
77
PendingOperatorApproval, // Operatör Onayı Bekliyor
88
Active, // Aktif Borç
99
PaymentConfirmationPending, // Ödeme Onayı Bekliyor

FinTrack/FinTrackForWindows.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343

4444
<ItemGroup>
4545
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
46+
<PackageReference Include="Emgu.CV.Bitmap" Version="4.11.0.5746" />
47+
<PackageReference Include="Emgu.CV.runtime.windows" Version="4.11.0.5746" />
4648
<PackageReference Include="LiveChartsCore.SkiaSharpView.WPF" Version="2.0.0-rc5.4" />
4749
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.6" />
4850
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.0-preview.6.25358.103">
@@ -56,10 +58,12 @@
5658
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.135" />
5759
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
5860
<PackageReference Include="Npgsql" Version="9.0.3" />
61+
<PackageReference Include="ReactiveUI.WPF" Version="20.4.1" />
5962
<PackageReference Include="Serilog.Extensions.Hosting" Version="9.0.1-dev-02307" />
6063
<PackageReference Include="Serilog.Settings.Configuration" Version="9.0.1-dev-02317" />
6164
<PackageReference Include="Serilog.Sinks.Debug" Version="3.0.0" />
6265
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
66+
<PackageReference Include="System.Drawing.Common" Version="9.0.7" />
6367
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.12.1" />
6468
</ItemGroup>
6569

FinTrack/Models/Debt/DebtModel.cs

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ public partial class DebtModel : ObservableObject
1111
public int BorrowerId { get; set; }
1212
public int CurrentUserId { get; set; }
1313

14+
public int? VideoMetadataId { get; set; }
15+
1416
[ObservableProperty]
1517
private string lenderName = string.Empty;
1618

@@ -21,14 +23,20 @@ public partial class DebtModel : ObservableObject
2123
private decimal amount;
2224

2325
[ObservableProperty]
26+
[NotifyPropertyChangedFor(nameof(CanMarkAsDefaulted))]
2427
private DateTime dueDate;
2528

2629
public string borrowerImageUrl = string.Empty;
2730

2831
public string lenderImageUrl = string.Empty;
2932

3033
[ObservableProperty]
31-
[NotifyPropertyChangedFor(nameof(StatusText), nameof(StatusBrush), nameof(IsActionRequiredForBorrower), nameof(IsRejected))]
34+
[NotifyPropertyChangedFor(nameof(StatusText))]
35+
[NotifyPropertyChangedFor(nameof(StatusBrush))]
36+
[NotifyPropertyChangedFor(nameof(IsActionRequiredForBorrower))]
37+
[NotifyPropertyChangedFor(nameof(IsRejected))]
38+
[NotifyPropertyChangedFor(nameof(IsVideoViewableForLender))]
39+
[NotifyPropertyChangedFor(nameof(CanMarkAsDefaulted))]
3240
private DebtStatusType status;
3341

3442
public bool IsCurrentUserTheBorrower => BorrowerId == CurrentUserId;
@@ -44,13 +52,14 @@ public partial class DebtModel : ObservableObject
4452

4553
public Brush StatusBrush => Status switch
4654
{
47-
DebtStatusType.Active => new SolidColorBrush(Colors.Green),
48-
DebtStatusType.Defaulted => new SolidColorBrush(Colors.DarkRed),
49-
DebtStatusType.AcceptedPendingVideoUpload => new SolidColorBrush(Colors.CornflowerBlue),
50-
DebtStatusType.PendingBorrowerAcceptance => new SolidColorBrush(Colors.DodgerBlue),
51-
DebtStatusType.PendingOperatorApproval => new SolidColorBrush(Colors.Orange),
52-
DebtStatusType.RejectedByOperator => new SolidColorBrush(Colors.Red),
53-
DebtStatusType.RejectedByBorrower => new SolidColorBrush(Colors.Red),
55+
DebtStatusType.Active => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#4CAF50")), // Green
56+
DebtStatusType.Defaulted => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#B71C1C")), // Dark Red
57+
DebtStatusType.AcceptedPendingVideoUpload => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#1E88E5")), // Blue
58+
DebtStatusType.PendingBorrowerAcceptance => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#03A9F4")), // Light Blue
59+
DebtStatusType.PendingOperatorApproval => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FB8C00")), // Orange
60+
DebtStatusType.RejectedByOperator => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#E53935")), // Red
61+
DebtStatusType.RejectedByBorrower => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#E53935")), // Red
62+
DebtStatusType.Paid => new SolidColorBrush(Colors.Gray),
5463
_ => new SolidColorBrush(Colors.Gray)
5564
};
5665

@@ -61,17 +70,32 @@ public partial class DebtModel : ObservableObject
6170
DebtStatusType.PendingOperatorApproval => "Operatör Onayı Bekleniyor",
6271
DebtStatusType.Active => "Aktif",
6372
DebtStatusType.Paid => "Ödendi",
64-
DebtStatusType.Defaulted => "Vadesi Geçmiş",
73+
DebtStatusType.Defaulted => "Vadesi Geçmiş - Temerrüt",
6574
DebtStatusType.RejectedByBorrower => "Tarafınızdan Reddedildi",
6675
DebtStatusType.RejectedByOperator => "Operatör Tarafından Reddedildi",
6776
_ => "Bilinmeyen Durum"
6877
};
6978

70-
// Borçlunun video yüklemesi gerekip gerekmediğini kontrol eder.
7179
public bool IsActionRequiredForBorrower =>
7280
Status == DebtStatusType.AcceptedPendingVideoUpload && IsCurrentUserTheBorrower;
7381

7482
public bool IsRejected =>
7583
Status == DebtStatusType.RejectedByBorrower || Status == DebtStatusType.RejectedByOperator;
84+
85+
/// <summary>
86+
/// "Teminat Videosunu İzle" düğmesinin görünür olup olmayacağını belirler.
87+
/// </summary>
88+
public bool IsVideoViewableForLender =>
89+
Status == DebtStatusType.Defaulted && // Durum 'Defaulted' olmalı
90+
IsCurrentUserTheLender && // Kullanıcı borç veren olmalı
91+
VideoMetadataId.HasValue; // İlişkili bir video olmalı
92+
93+
/// <summary>
94+
/// "Temerrüde Düştü Olarak İşaretle" düğmesinin görünür olup olmayacağını belirleyecek.
95+
/// </summary>
96+
public bool CanMarkAsDefaulted =>
97+
Status == DebtStatusType.Active && // Durum 'Active' olmalı
98+
IsCurrentUserTheLender && // Kullanıcı borç veren olmalı
99+
DueDate < DateTime.Now; // Vadesi geçmiş olmalı
76100
}
77101
}

FinTrack/Services/Api/ApiService.cs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public ApiService(ILogger<ApiService> logger, IConfiguration configuration)
2525
_logger = logger;
2626
_configuration = configuration;
2727

28-
_baseUrl = "http://localhost:5000/";
28+
_baseUrl = "http://localhost:8090/";
2929
//_baseUrl = _configuration["BaseServerUrl"];
3030
_httpClient = new HttpClient
3131
{
@@ -381,5 +381,36 @@ public async Task<bool> UploadFileAsync(string endpoint, string filePath)
381381
throw;
382382
}
383383
}
384+
385+
public async Task<(Stream? Stream, string? ContentType, string? FileName)> StreamFileAsync(string endpoint)
386+
{
387+
_logger.LogInformation("Streaming file request started: {Endpoint}", endpoint);
388+
try
389+
{
390+
AddAuthorizationHeader();
391+
392+
var response = await _httpClient.GetAsync(endpoint, HttpCompletionOption.ResponseHeadersRead);
393+
394+
response.EnsureSuccessStatusCode();
395+
396+
var stream = await response.Content.ReadAsStreamAsync();
397+
398+
var contentType = response.Content.Headers.ContentType?.ToString();
399+
var fileName = response.Content.Headers.ContentDisposition?.FileName?.Trim('"');
400+
401+
_logger.LogInformation("File stream successfully retrieved from {Endpoint}", endpoint);
402+
return (stream, contentType, fileName);
403+
}
404+
catch (HttpRequestException ex)
405+
{
406+
_logger.LogError(ex, "HTTP error during file stream: {Endpoint}. Status: {StatusCode}", endpoint, ex.StatusCode);
407+
return (null, null, null);
408+
}
409+
catch (Exception ex)
410+
{
411+
_logger.LogError(ex, "Generic error during file stream: {Endpoint}", endpoint);
412+
return (null, null, null);
413+
}
414+
}
384415
}
385416
}

FinTrack/Services/Api/IApiService.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
namespace FinTrackForWindows.Services.Api
1+
using System.IO;
2+
3+
namespace FinTrackForWindows.Services.Api
24
{
35
public interface IApiService
46
{
@@ -9,5 +11,6 @@ public interface IApiService
911
Task<bool> CreateCategoryAsync(string endpoint, object payload);
1012
Task<bool> UploadFileAsync(string endpoint, string filePath);
1113
Task<(byte[] FileBytes, string FileName)?> PostAndDownloadReportAsync<T>(string endpoint, T payload);
14+
Task<(Stream? Stream, string? ContentType, string? FileName)> StreamFileAsync(string endpoint);
1215
}
1316
}

FinTrack/Services/AuthService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public AuthService(IConfiguration configuration)
1616
_configuration = configuration;
1717
_httpClient = new HttpClient
1818
{
19-
BaseAddress = new Uri("http://localhost:5000/")
19+
BaseAddress = new Uri("http://localhost:8090/")
2020
//BaseAddress = new Uri(_configuration["BaseServerUrl"])
2121
};
2222

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
using Emgu.CV;
2+
using Emgu.CV.CvEnum;
3+
using Microsoft.Extensions.Logging;
4+
using System.Drawing.Imaging;
5+
using System.IO;
6+
using System.Windows.Media.Imaging;
7+
using System.Windows.Threading;
8+
9+
namespace FinTrackForWindows.Services.Camera
10+
{
11+
public class CameraService : ICameraService
12+
{
13+
private VideoCapture? _capture;
14+
private VideoWriter? _writer;
15+
private DispatcherTimer? _timer;
16+
17+
private readonly ILogger<CameraService> _logger;
18+
19+
public Action<BitmapSource>? OnFrameReady { get; set; }
20+
21+
public CameraService(ILogger<CameraService> logger)
22+
{
23+
_logger = logger;
24+
}
25+
26+
public bool InitializeCamera(int cameraIndex = 0)
27+
{
28+
try
29+
{
30+
_capture = new VideoCapture(cameraIndex);
31+
if (!_capture.IsOpened) return false;
32+
33+
double fps = _capture.Get(CapProp.Fps);
34+
_timer = new DispatcherTimer
35+
{
36+
Interval = TimeSpan.FromMilliseconds(1000 / (fps > 0 ? fps : 30))
37+
};
38+
_timer.Tick += Timer_Tick;
39+
_timer.Start();
40+
return true;
41+
}
42+
catch (Exception ex)
43+
{
44+
_logger.LogError(ex, "Failed to initialize camera.");
45+
return false;
46+
}
47+
}
48+
49+
private void Timer_Tick(object? sender, EventArgs e)
50+
{
51+
if (_capture == null || !_capture.IsOpened) return;
52+
53+
using (Mat frame = _capture.QueryFrame())
54+
{
55+
if (frame != null)
56+
{
57+
OnFrameReady?.Invoke(ConvertMatToBitmapSource(frame));
58+
59+
if (_writer != null && _writer.IsOpened)
60+
{
61+
_writer.Write(frame);
62+
}
63+
}
64+
}
65+
}
66+
67+
public string StartRecording()
68+
{
69+
if (_capture == null || !_capture.IsOpened)
70+
throw new InvalidOperationException("Camera is not initialized.");
71+
72+
string tempPath = Path.GetTempPath();
73+
string outputFilePath = Path.Combine(tempPath, $"debt_video_{Guid.NewGuid()}.mp4");
74+
75+
int frameWidth = (int)_capture.Get(CapProp.FrameWidth);
76+
int frameHeight = (int)_capture.Get(CapProp.FrameHeight);
77+
double fps = _capture.Get(CapProp.Fps);
78+
79+
_writer = new VideoWriter(outputFilePath, VideoWriter.Fourcc('X', '2', '6', '4'), fps > 0 ? fps : 30, new System.Drawing.Size(frameWidth, frameHeight), true);
80+
return outputFilePath;
81+
}
82+
83+
public void StopRecording()
84+
{
85+
_writer?.Dispose();
86+
_writer = null;
87+
}
88+
89+
public void Release()
90+
{
91+
_timer?.Stop();
92+
_capture?.Dispose();
93+
_writer?.Dispose();
94+
}
95+
96+
public void Dispose()
97+
{
98+
Release();
99+
GC.SuppressFinalize(this);
100+
}
101+
102+
private static BitmapSource ConvertMatToBitmapSource(Mat image)
103+
{
104+
using var bitmap = image.ToBitmap();
105+
using var stream = new MemoryStream();
106+
bitmap.Save(stream, ImageFormat.Bmp);
107+
stream.Position = 0;
108+
var bitmapImage = new BitmapImage();
109+
bitmapImage.BeginInit();
110+
bitmapImage.StreamSource = stream;
111+
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
112+
bitmapImage.EndInit();
113+
bitmapImage.Freeze();
114+
return bitmapImage;
115+
}
116+
}
117+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System.Windows.Media.Imaging;
2+
3+
namespace FinTrackForWindows.Services.Camera
4+
{
5+
public interface ICameraService : IDisposable
6+
{
7+
Action<BitmapSource> OnFrameReady { get; set; }
8+
bool InitializeCamera(int cameraIndex = 0);
9+
string StartRecording();
10+
void StopRecording();
11+
void Release();
12+
}
13+
}

0 commit comments

Comments
 (0)