Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions PolyPilot/Components/Layout/SessionSidebar.razor
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,10 @@
</button>
}
<span class="mobile-title"><img src="PolyPilot_text.png" height="22" style="vertical-align:middle" /></span>
<span class="mobile-font-controls">
<button class="mobile-font-btn" @onclick="DecreaseFontSize" disabled="@(FontSize <= 12)">A−</button>
<button class="mobile-font-btn" @onclick="IncreaseFontSize" disabled="@(FontSize >= 24)">A+</button>
</span>
<span class="mobile-title"><img src="PolyPilot_text.png" height="20" style="vertical-align:middle" /></span>
<div class="mobile-tabs">
<a href="/" class="mobile-tab @(currentPage == "/" || currentPage == "/dashboard" ? "active" : "")" @onclick='() => { CopilotService.SaveUiState("/"); currentPage = "/"; }'>Dashboard</a>
<a href="/settings" class="mobile-tab @(currentPage == "/settings" ? "active" : "")" @onclick='() => { CopilotService.SaveUiState("/settings"); currentPage = "/settings"; }'><svg style="vertical-align:middle" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg></a>
<a href="/" class="mobile-tab @(currentPage == "/" || currentPage == "/dashboard" ? "active" : "")" @onclick='() => { CopilotService.SaveUiState("/"); currentPage = "/"; }' title="Dashboard"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="9"/><rect x="14" y="3" width="7" height="5"/><rect x="14" y="12" width="7" height="9"/><rect x="3" y="16" width="7" height="5"/></svg></a>
<a href="/settings" class="mobile-tab @(currentPage == "/settings" ? "active" : "")" @onclick='() => { CopilotService.SaveUiState("/settings"); currentPage = "/settings"; }' title="Settings"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg></a>
</div>
</div>
}
Expand All @@ -33,6 +29,8 @@ else if (IsFlyoutPanel)
<button class="flyout-close-btn" @onclick="ToggleFlyout">✕</button>
</div>

@if (!PlatformHelper.IsMobile)
{
<div class="new-session-wrapper">
<CreateSessionForm @ref="createSessionFormRef" @bind-SessionName="newSessionName"
@bind-SelectedModel="selectedModel"
Expand All @@ -44,6 +42,7 @@ else if (IsFlyoutPanel)
</div>

<div class="sidebar-divider"></div>
}
@RenderSortToolbar
@RenderSessionList
</div>
Expand Down
21 changes: 8 additions & 13 deletions PolyPilot/Components/Layout/SessionSidebar.razor.css
Original file line number Diff line number Diff line change
Expand Up @@ -927,7 +927,7 @@
display: flex;
align-items: center;
gap: 0.5rem;
padding: calc(env(safe-area-inset-top, 0px) + 0.6rem) 0.75rem 0.6rem;
padding: calc(env(safe-area-inset-top, 0px) + 0.5rem) 0.75rem 0.5rem;
color: var(--text-primary);
overflow: hidden;
max-width: 100vw;
Expand All @@ -938,7 +938,7 @@
border: none;
color: rgba(200,216,240,0.6);
cursor: pointer;
padding: 0.4rem;
padding: 0.3rem;
display: flex;
align-items: center;
font-size: var(--type-title3);
Expand All @@ -958,30 +958,25 @@

.mobile-tabs {
display: flex;
gap: 0.25rem;
gap: 0.15rem;
margin-left: auto;
background: var(--hover-bg);
border-radius: 8px;
padding: 0.15rem;
flex-shrink: 0;
}

.mobile-tab {
padding: 0.3rem 0.7rem;
padding: 0.35rem;
border-radius: 6px;
background: transparent;
color: rgba(200,216,240,0.5);
color: rgba(200,216,240,0.4);
text-decoration: none;
font-size: var(--type-subhead);
font-weight: 500;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
-webkit-tap-highlight-color: transparent;
}

.mobile-tab.active {
background: rgba(59, 130, 246, 0.2);
color: var(--accent-primary);
font-weight: 600;
}

/* Mobile font size controls */
Expand Down
81 changes: 78 additions & 3 deletions PolyPilot/Components/Pages/Dashboard.razor
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
@inject DevTunnelService DevTunnelService
@inject WsBridgeServer WsBridgeServer
@inject GitAutoUpdateService GitAutoUpdate
@inject QrScannerService QrScanner
@implements IAsyncDisposable

<div class="dashboard @(expandedSession != null ? "expanded-mode" : "")">
Expand All @@ -23,17 +24,32 @@
<span>Restoring sessions…</span>
</div>
}
@if (!string.IsNullOrEmpty(initError))
@if (!string.IsNullOrEmpty(initError) && !PlatformHelper.IsMobile)
{
<div class="init-error-card">
<span class="init-error-icon">⚠️</span>
<p class="init-error-text">@initError</p>
<button class="retry-btn" @onclick="Initialize">Retry</button>
</div>
}
@if (PlatformHelper.IsMobile)
@if (PlatformHelper.IsMobile && !CopilotService.IsInitialized)
{
<button class="connect-btn" @onclick='() => Nav.NavigateTo("/settings")'>Connect to Remote Server</button>
<div class="mobile-connect-card">
<button class="scan-qr-btn" @onclick="DashboardScanQr">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/><circle cx="12" cy="13" r="4"/></svg>
Scan QR Code
</button>
<div class="mobile-connect-divider"><span>or enter manually</span></div>
<input type="text" class="mobile-connect-input" placeholder="Server URL" @bind="mobileRemoteUrl" />
<input type="password" class="mobile-connect-input" placeholder="Token" @bind="mobileRemoteToken" />
<button class="mobile-connect-go" @onclick="DashboardConnect" disabled="@mobileConnecting">
@(mobileConnecting ? "Connecting…" : "Connect")
</button>
@if (!string.IsNullOrEmpty(mobileConnectError))
{
<p class="mobile-connect-error">@mobileConnectError</p>
}
</div>
}
</div>
}
Expand Down Expand Up @@ -201,6 +217,10 @@
private Dictionary<string, int> historyIndexBySession = new();
private int fontSize = 20;
private string? expandedSession;
private string mobileRemoteUrl = "";
private string mobileRemoteToken = "";
private bool mobileConnecting;
private string? mobileConnectError;
private bool _needsScrollToBottom;
private bool isCompactGrid; // true = compact cards, false = spacious cards
private bool toolbarMenuOpen;
Expand Down Expand Up @@ -232,6 +252,14 @@
CopilotService.OnTurnEnd += HandleTurnEnd;

await Initialize();

// Pre-fill remote connection fields from saved settings
if (PlatformHelper.IsMobile)
{
var cs = ConnectionSettings.Load();
mobileRemoteUrl = cs.RemoteUrl ?? "";
mobileRemoteToken = cs.RemoteToken ?? "";
}
}

private async Task Initialize()
Expand Down Expand Up @@ -362,6 +390,53 @@
}
}

private async Task DashboardScanQr()
{
var result = await QrScanner.ScanAsync();
if (string.IsNullOrEmpty(result)) return;

try
{
var doc = System.Text.Json.JsonDocument.Parse(result);
if (doc.RootElement.TryGetProperty("url", out var urlProp))
mobileRemoteUrl = urlProp.GetString() ?? "";
if (doc.RootElement.TryGetProperty("token", out var tokenProp))
mobileRemoteToken = tokenProp.GetString() ?? "";
}
catch
{
mobileRemoteUrl = result;
}

// Auto-connect after scan
await DashboardConnect();
}

private async Task DashboardConnect()
{
if (string.IsNullOrWhiteSpace(mobileRemoteUrl)) return;
mobileConnecting = true;
mobileConnectError = null;
StateHasChanged();

try
{
var connSettings = ConnectionSettings.Load();
connSettings.Mode = ConnectionMode.Remote;
connSettings.RemoteUrl = mobileRemoteUrl;
connSettings.RemoteToken = mobileRemoteToken;
connSettings.Save();
await CopilotService.ReconnectAsync(connSettings);
}
catch (Exception ex)
{
mobileConnectError = ex.Message;
}

mobileConnecting = false;
StateHasChanged();
}

protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
Expand Down
75 changes: 75 additions & 0 deletions PolyPilot/Components/Pages/Dashboard.razor.css
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,81 @@
border-color: var(--border-accent);
}

/* Mobile inline connect card */
.mobile-connect-card {
display: flex;
flex-direction: column;
gap: 0.6rem;
width: 100%;
max-width: 320px;
margin-top: 0.5rem;
}

.scan-qr-btn {
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
padding: 0.7rem 1rem;
border: 1px solid var(--accent-primary, #7c5cfc);
border-radius: 12px;
background: var(--accent-primary, #7c5cfc);
color: #fff;
font-size: var(--type-body);
font-weight: 600;
cursor: pointer;
}

.mobile-connect-divider {
display: flex;
align-items: center;
gap: 0.6rem;
color: var(--text-dim, #5a6a7a);
font-size: 0.75rem;
}
.mobile-connect-divider::before,
.mobile-connect-divider::after {
content: '';
flex: 1;
height: 1px;
background: var(--control-border, #2a2a3a);
}

.mobile-connect-input {
padding: 0.55rem 0.75rem;
border: 1px solid var(--control-border, #2a2a3a);
border-radius: 8px;
background: var(--bg-input, #1a1a2e);
color: var(--text-primary);
font-size: var(--type-body);
outline: none;
}
.mobile-connect-input:focus {
border-color: var(--accent-primary, #7c5cfc);
}

.mobile-connect-go {
padding: 0.6rem 1rem;
border: 1px solid var(--border-accent, #7c5cfc44);
border-radius: 12px;
background: var(--hover-bg, #1a1a2e);
color: var(--accent-primary, #7c5cfc);
font-size: var(--type-body);
font-weight: 500;
cursor: pointer;
}
.mobile-connect-go:disabled {
opacity: 0.5;
cursor: not-allowed;
}

.mobile-connect-error {
color: var(--error-text, #ff6b6b);
font-size: 0.8rem;
text-align: center;
margin: 0;
}

.initializing {
display: flex;
flex-direction: column;
Expand Down
38 changes: 37 additions & 1 deletion PolyPilot/Components/Pages/Settings.razor
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
</div>
</div>

@if (!PlatformHelper.IsMobile || CopilotService.IsInitialized)
{
<div class="settings-group @(GroupVisible("connection") ? "" : "search-hidden")">
<h2 class="group-title">Connection</h2>

Expand Down Expand Up @@ -283,6 +285,7 @@
</div>
</div>
</div>
}

@if (settings.Mode != ConnectionMode.Remote && settings.Mode != ConnectionMode.Demo)
{
Expand Down Expand Up @@ -377,6 +380,15 @@
</div>
</div>
</div>

<div class="settings-section @(SectionVisible("font size text zoom") ? "" : "search-hidden")">
<h3>Font Size</h3>
<div class="font-size-control">
<button class="font-size-btn" @onclick="DecreaseFontSize" disabled="@(fontSize <= 12)">A‒</button>
<span class="font-size-value">@fontSize px</span>
<button class="font-size-btn" @onclick="IncreaseFontSize" disabled="@(fontSize >= 24)">A+</button>
</div>
</div>
</div>

@if (GitAutoUpdate.IsAvailable)
Expand Down Expand Up @@ -428,6 +440,7 @@
private (string? builtInPath, string? builtInVersion, string? systemPath, string? systemVersion) cliInfo;
private CliSourceMode _initialCliSource;
private bool cliSourceChanged;
private int fontSize = 20;

[JSInvokable]
public void JsUpdateSearch(string query)
Expand Down Expand Up @@ -459,7 +472,7 @@
return groupKeyword switch
{
"connection" => SectionVisible("transport mode embedded persistent remote server port start stop pid devtunnel share tunnel mobile qr url token connect save reconnect"),
"ui" => SectionVisible("chat message layout default reversed both left theme"),
"ui" => SectionVisible("chat message layout default reversed both left theme font size text zoom"),
"developer" => SectionVisible("auto update main git watch relaunch rebuild"),
_ => true
};
Expand Down Expand Up @@ -490,6 +503,9 @@
DevTunnelService.OnStateChanged += OnTunnelStateChanged;
GitAutoUpdate.OnStateChanged += OnAutoUpdateStateChanged;

var uiState = CopilotService.LoadUiState();
if (uiState?.FontSize > 0) fontSize = uiState.FontSize;

if (DevTunnelService.State == TunnelState.Running && DevTunnelService.TunnelUrl != null)
GenerateQrCode(DevTunnelService.TunnelUrl, DevTunnelService.AccessToken);

Expand Down Expand Up @@ -739,6 +755,26 @@
ShowStatus("Layout updated", "success");
}

private async Task IncreaseFontSize()
{
if (fontSize >= 24) return;
fontSize = Math.Min(fontSize + 2, 24);
await ApplyFontSize();
}

private async Task DecreaseFontSize()
{
if (fontSize <= 12) return;
fontSize = Math.Max(fontSize - 2, 12);
await ApplyFontSize();
}

private async Task ApplyFontSize()
{
await JS.InvokeVoidAsync("eval", $"document.documentElement.style.setProperty('--app-font-size', '{fontSize}px')");
CopilotService.SaveUiState("/settings", fontSize: fontSize);
}

private void ToggleAutoUpdate()
{
if (GitAutoUpdate.IsEnabled)
Expand Down
Loading