Skip to content

Commit cfa2983

Browse files
committed
feat: improve login
1 parent 0d59a03 commit cfa2983

5 files changed

Lines changed: 596 additions & 77 deletions

File tree

TelegramDownloader/Models/SystemMetrics.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Diagnostics;
2+
using System.Globalization;
23
using System.Runtime.InteropServices;
34

45
namespace TelegramDownloader.Models
@@ -28,7 +29,7 @@ public class SystemMetrics
2829
public long DiskFreeBytes { get; set; }
2930
public double DiskUsagePercent { get; set; }
3031

31-
// Formatted strings
32+
// Formatted strings for display
3233
public string TotalMemory => FormatBytes(TotalMemoryBytes);
3334
public string UsedMemory => FormatBytes(UsedMemoryBytes);
3435
public string AvailableMemory => FormatBytes(AvailableMemoryBytes);
@@ -39,6 +40,18 @@ public class SystemMetrics
3940
public string DiskUsed => FormatBytes(DiskUsedBytes);
4041
public string DiskFree => FormatBytes(DiskFreeBytes);
4142

43+
// CSS-safe formatted values (always use dot as decimal separator)
44+
public string AppCpuUsageCss => AppCpuUsage.ToString("F1", CultureInfo.InvariantCulture);
45+
public string SystemCpuUsageCss => SystemCpuUsage.ToString("F1", CultureInfo.InvariantCulture);
46+
public string MemoryUsagePercentCss => MemoryUsagePercent.ToString("F1", CultureInfo.InvariantCulture);
47+
public string DiskUsagePercentCss => DiskUsagePercent.ToString("F1", CultureInfo.InvariantCulture);
48+
public string AppMemoryPercentCss => TotalMemoryBytes > 0
49+
? ((double)AppMemoryBytes / TotalMemoryBytes * 100).ToString("F1", CultureInfo.InvariantCulture)
50+
: "0";
51+
public string TempFolderPercentCss => DiskTotalBytes > 0
52+
? ((double)TempFolderSizeBytes / DiskTotalBytes * 100).ToString("F1", CultureInfo.InvariantCulture)
53+
: "0";
54+
4255
private static string FormatBytes(long bytes)
4356
{
4457
string[] suffixes = { "B", "KB", "MB", "GB", "TB" };

TelegramDownloader/Pages/Index.razor

Lines changed: 139 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@layout EmptyLayout
1+
@layout EmptyLayout
22
@page "/"
33
@implements IDisposable
44

@@ -11,101 +11,153 @@
1111
@inject IJSRuntime JSRuntime;
1212
@inject PreloadService preloadService
1313

14-
<style>
15-
.form-signin {
16-
width: 100%;
17-
max-width: 330px;
18-
padding: 15px;
19-
margin: auto;
20-
}
21-
22-
.buttons {
23-
padding-top: inherit;
24-
}
25-
</style>
2614
<Preload LoadingText="Loading..." />
2715
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/intl-tel-input@23.0.12/build/css/intlTelInput.css">
16+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css">
17+
18+
<PageTitle>Login - Telegram File Manager</PageTitle>
19+
20+
<div class="login-page">
21+
<div class="login-card">
22+
@if (Model != null && Model.type != null)
23+
{
24+
<!-- Logo -->
25+
<div class="logo-container">
26+
<img src="https://upload.wikimedia.org/wikipedia/commons/8/82/Telegram_logo.svg" alt="Telegram logo" />
27+
</div>
2828

29-
<PageTitle>Login</PageTitle>
29+
<!-- Title based on step -->
30+
@switch (Model.type)
31+
{
32+
case "phone":
33+
<h1 class="login-title">Welcome</h1>
34+
<p class="login-subtitle">Enter your phone number to get started</p>
35+
break;
36+
case "vc":
37+
<h1 class="login-title">Verification</h1>
38+
<p class="login-subtitle">Enter the code sent to your phone</p>
39+
break;
40+
case "pass":
41+
<h1 class="login-title">Two-Factor Auth</h1>
42+
<p class="login-subtitle">Enter your 2FA password</p>
43+
break;
44+
case "ok":
45+
<h1 class="login-title">Welcome Back!</h1>
46+
<p class="login-subtitle">You are successfully authenticated</p>
47+
break;
48+
}
3049

31-
@if (Model != null && Model.type != null)
32-
{
33-
<div class="container form-signin">
34-
<div class="text-center">
35-
<img src="https://static.vecteezy.com/system/resources/previews/023/986/534/large_2x/telegram-logo-telegram-logo-transparent-telegram-icon-transparent-free-free-png.png" alt="Telegram logo" style="max-width: -webkit-fill-available;" />
50+
<!-- Step indicator -->
51+
<div class="step-indicator">
52+
<div class="step @(Model.type == "phone" ? "active" : "completed")"></div>
53+
<div class="step @(Model.type == "vc" ? "active" : (Model.type == "pass" || Model.type == "ok" ? "completed" : ""))"></div>
54+
<div class="step @(Model.type == "pass" ? "active" : (Model.type == "ok" ? "completed" : ""))"></div>
55+
<div class="step @(Model.type == "ok" ? "active completed" : "")"></div>
56+
</div>
3657

37-
<EditForm class="form-signin mb-4" Model="Model" OnSubmit="Submit" FormName="LoginModel">
58+
<EditForm class="login-form" Model="Model" OnSubmit="Submit" FormName="LoginModel">
3859
@switch (Model.type)
3960
{
4061
case "phone":
4162
<div class="form-group">
42-
<label for="phone">Teléfono</label>
43-
<InputText class="form-control" id="phone" type="text" @bind-Value="Model!.value" aria-describedby="phone" maxlength="12" data-mask="+00.000.00.00.00" placeholder="Teléfono" />
63+
<label for="phone"><i class="bi bi-telephone"></i> Phone Number</label>
64+
<InputText class="form-control" id="phone" type="text" @bind-Value="Model!.value"
65+
aria-describedby="phone" maxlength="15" placeholder="+34 600 000 000" />
4466
</div>
4567
break;
4668
case "vc":
4769
<div class="form-group">
48-
<label for="code">Código</label>
49-
<InputText class="form-control" id="code" maxlength="5" type="text" @bind-Value="Model!.value" />
70+
<label for="code"><i class="bi bi-shield-lock"></i> Verification Code</label>
71+
<InputText class="form-control" id="code" maxlength="5" type="text"
72+
@bind-Value="Model!.value" placeholder="12345" autocomplete="one-time-code" />
5073
</div>
5174
break;
5275
case "pass":
5376
<div class="form-group">
54-
<label for="pass">Contraseña</label>
55-
<InputText class="form-control" id="pass" type="password" @bind-Value="Model!.value" />
77+
<label for="pass"><i class="bi bi-key"></i> Password</label>
78+
<InputText class="form-control" id="pass" type="password"
79+
@bind-Value="Model!.value" placeholder="Enter your 2FA password" />
5680
</div>
5781
break;
5882
case "ok":
59-
<span> Authenticado </span>
83+
<div class="text-center">
84+
<div class="success-badge">
85+
<i class="bi bi-check-circle-fill"></i>
86+
<span>Authenticated</span>
87+
</div>
88+
</div>
6089
break;
6190
}
62-
<div class="form-group buttons">
6391

92+
<div class="button-group">
6493
@if (Model.type == "ok")
6594
{
66-
<button class="btn btn-info" @onclick="Salir" type="button">Desconectar</button>
95+
<button class="btn-danger-custom" @onclick="Salir" type="button">
96+
<i class="bi bi-box-arrow-right"></i> Disconnect
97+
</button>
6798
}
6899
else
69100
{
70-
<button class="btn btn-info" type="submit">Send</button>
101+
<button class="btn-primary-custom" type="submit">
102+
@if (Model.type == "phone")
103+
{
104+
<span>Continue</span>
105+
<i class="bi bi-arrow-right"></i>
106+
}
107+
else
108+
{
109+
<span>Verify</span>
110+
<i class="bi bi-check-lg"></i>
111+
}
112+
</button>
71113
@if (Model.type != null && Model.type != "phone")
72114
{
73-
<button class="btn btn-warning" @onclick="Cancel">Cancel</button>
115+
<button class="btn-secondary-custom" type="button" @onclick="Cancel">
116+
Cancel
117+
</button>
74118
}
75119
}
76120
</div>
121+
77122
@if (!string.IsNullOrEmpty(imageString))
78123
{
79-
<img src="data:image;base64, @imageString" />
124+
<div class="qr-container">
125+
<img src="data:image;base64, @imageString" alt="QR Code" />
126+
</div>
80127
}
81-
82128
</EditForm>
83-
84-
85-
86-
</div>
87-
</div>
88-
} else
89-
{
90-
<div class="container form-signin">
91-
<h3>Checking user data</h3>
92-
<div class="text-center">
93-
<img src="https://static.vecteezy.com/system/resources/previews/023/986/534/large_2x/telegram-logo-telegram-logo-transparent-telegram-icon-transparent-free-free-png.png" alt="Telegram logo" style="max-width: -webkit-fill-available;" />
94-
</div>
95-
</div>
96-
}
97129

98-
99-
@*
100-
101-
<SurveyPrompt Title="How is Blazor working for you?" /> *@
130+
<div class="login-footer">
131+
Telegram File Manager
132+
</div>
133+
}
134+
else
135+
{
136+
<!-- Loading/Checking state -->
137+
<div class="loading-container">
138+
<div class="loading-spinner">
139+
<img class="loading-logo" src="https://upload.wikimedia.org/wikipedia/commons/8/82/Telegram_logo.svg" alt="Telegram" />
140+
</div>
141+
<p class="loading-text">
142+
Checking session
143+
<span class="loading-dots">
144+
<span></span>
145+
<span></span>
146+
<span></span>
147+
</span>
148+
</p>
149+
<p class="loading-subtext">Please wait while we verify your credentials</p>
150+
</div>
151+
}
152+
</div>
153+
</div>
102154

103155
@code {
104-
// [SupplyParameterFromForm]
105156
public LoginModel? Model { get; set; } = null;
106157
private CancellationToken cTokenQr { get; set; }
107158
CancellationTokenSource source { get; set; }
108159
private string imageString { get; set; }
160+
private string lastFocusedType = null;
109161

110162
protected override async Task OnInitializedAsync()
111163
{
@@ -122,36 +174,65 @@
122174
}
123175
}
124176

125-
126177
protected override async Task OnAfterRenderAsync(bool firstRender)
127178
{
128-
if (Model.type != null && Model.type == "phone")
129-
await JSRuntime.InvokeVoidAsync("loadCountries");
179+
if (Model?.type != null && Model.type != "ok" && Model.type != lastFocusedType)
180+
{
181+
lastFocusedType = Model.type;
182+
183+
if (Model.type == "phone")
184+
{
185+
await JSRuntime.InvokeVoidAsync("loadCountries");
186+
await Task.Delay(100); // Small delay to ensure intl-tel-input is initialized
187+
}
130188

189+
await FocusCurrentInput();
190+
}
131191
}
132192

193+
private async Task FocusCurrentInput()
194+
{
195+
try
196+
{
197+
string elementId = Model?.type switch
198+
{
199+
"phone" => "phone",
200+
"vc" => "code",
201+
"pass" => "pass",
202+
_ => null
203+
};
133204

205+
if (elementId != null)
206+
{
207+
await JSRuntime.InvokeVoidAsync("focusElement", elementId);
208+
}
209+
}
210+
catch
211+
{
212+
// Element might not be rendered yet
213+
}
214+
}
134215

135216
private async void Submit()
136217
{
137218
if (Model.type == "phone")
138219
{
139220
var phone = await JSRuntime.InvokeAsync<string>("getNumber");
140221
Model.type = await ts.checkAuth(phone, Model.type == "phone") ?? "phone";
141-
} else
222+
}
223+
else
142224
{
143225
Model.type = await ts.checkAuth(Model.value, Model.type == "phone");
144226
}
145227

146228
Model.value = "";
147229
StateHasChanged();
148230
await isLogin();
149-
// Logger.LogInformation("Id = {Id}", Model?.Id);
150231
}
151232

152233
private async Task isLogin()
153234
{
154-
if (Model.type == "ok")
235+
if (Model.type == "ok")
155236
{
156237
if (source != null)
157238
{
@@ -161,15 +242,6 @@
161242
}
162243
}
163244
NavManager.NavigateTo("/fetchdata");
164-
} else
165-
{
166-
// source = new CancellationTokenSource();
167-
// cTokenQr = source.Token;
168-
// var user = await ts.CallQrGenerator(GenerateQR, cTokenQr, true);
169-
// if (user != null)
170-
// {
171-
// NavManager.NavigateTo("/fetchdata");
172-
// }
173245
}
174246
}
175247

@@ -191,7 +263,6 @@
191263
Model.value = "";
192264
Model.type = "phone";
193265
StateHasChanged();
194-
// Logger.LogInformation("Id = {Id}", Model?.Id);
195266
}
196267

197268
private async void Cancel()

0 commit comments

Comments
 (0)