Skip to content

Commit e782fd9

Browse files
sharpninjaCopilot
andcommitted
Add connection dialog for Android host/port configuration
Android app now shows a connection dialog on launch where the user enters the MCP server hostname and port. On Connect, the main view is loaded with the specified server URL. Added ConnectionViewModel in Core and ConnectionDialogView in the Android project. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 4b4a78d commit e782fd9

5 files changed

Lines changed: 159 additions & 6 deletions

File tree

src/RequestTracker.Android/App.axaml.cs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Avalonia;
2+
using Avalonia.Controls;
23
using Avalonia.Controls.ApplicationLifetimes;
34
using Avalonia.Data.Core.Plugins;
45
using Avalonia.Markup.Xaml;
@@ -25,12 +26,28 @@ public override void OnFrameworkInitializationCompleted()
2526

2627
try
2728
{
28-
var clipboardService = new AndroidClipboardService();
29-
var vm = new MainWindowViewModel(clipboardService);
30-
singleView.MainView = DeviceFormFactor.IsTablet()
31-
? new TabletMainView { DataContext = vm }
32-
: (Avalonia.Controls.Control)new PhoneMainView { DataContext = vm };
33-
vm.InitializeAfterWindowShown();
29+
var connectionVm = new ConnectionViewModel();
30+
var connectionView = new ConnectionDialogView { DataContext = connectionVm };
31+
singleView.MainView = connectionView;
32+
33+
connectionVm.Connected += mcpBaseUrl =>
34+
{
35+
try
36+
{
37+
var clipboardService = new AndroidClipboardService();
38+
var vm = new MainWindowViewModel(clipboardService, mcpBaseUrl);
39+
singleView.MainView = DeviceFormFactor.IsTablet()
40+
? new TabletMainView { DataContext = vm }
41+
: (Control)new PhoneMainView { DataContext = vm };
42+
vm.InitializeAfterWindowShown();
43+
}
44+
catch (Exception ex)
45+
{
46+
Console.Error.WriteLine($"Connection failed: {ex}");
47+
connectionVm.ErrorMessage = $"Connection failed: {ex.Message}";
48+
connectionVm.IsConnecting = false;
49+
}
50+
};
3451
}
3552
catch (Exception ex)
3653
{
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<UserControl xmlns="https://github.com/avaloniaui"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
xmlns:vm="using:RequestTracker.Core.ViewModels"
4+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6+
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="600"
7+
x:Class="RequestTracker.Android.Views.ConnectionDialogView"
8+
x:DataType="vm:ConnectionViewModel">
9+
10+
<Grid VerticalAlignment="Center" HorizontalAlignment="Center"
11+
MaxWidth="360" Margin="24">
12+
<Border Background="{DynamicResource SystemControlBackgroundChromeMediumLowBrush}"
13+
CornerRadius="12" Padding="28" BoxShadow="0 4 16 0 #40000000">
14+
<StackPanel Spacing="16">
15+
<!-- Title -->
16+
<TextBlock Text="Connect to Server"
17+
FontSize="22" FontWeight="SemiBold"
18+
HorizontalAlignment="Center" Margin="0,0,0,8"/>
19+
20+
<TextBlock Text="Enter the hostname and port of the MCP session log server."
21+
TextWrapping="Wrap" FontSize="13" Foreground="Gray"
22+
HorizontalAlignment="Center" TextAlignment="Center"
23+
Margin="0,0,0,4"/>
24+
25+
<!-- Host -->
26+
<StackPanel Spacing="4">
27+
<TextBlock Text="Host" FontSize="13" FontWeight="Medium"/>
28+
<TextBox Text="{Binding Host}"
29+
Watermark="e.g. 192.168.1.100"
30+
FontSize="16" Padding="10,8"
31+
IsEnabled="{Binding !IsConnecting}"/>
32+
</StackPanel>
33+
34+
<!-- Port -->
35+
<StackPanel Spacing="4">
36+
<TextBlock Text="Port" FontSize="13" FontWeight="Medium"/>
37+
<TextBox Text="{Binding Port}"
38+
Watermark="e.g. 5000"
39+
FontSize="16" Padding="10,8"
40+
IsEnabled="{Binding !IsConnecting}"/>
41+
</StackPanel>
42+
43+
<!-- Error -->
44+
<TextBlock Text="{Binding ErrorMessage}"
45+
Foreground="Red" FontSize="13"
46+
TextWrapping="Wrap"
47+
IsVisible="{Binding ErrorMessage, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
48+
49+
<!-- Connect Button -->
50+
<Button Content="Connect"
51+
Command="{Binding ConnectCommand}"
52+
HorizontalAlignment="Stretch"
53+
HorizontalContentAlignment="Center"
54+
FontSize="16" FontWeight="SemiBold"
55+
Padding="0,12"
56+
IsEnabled="{Binding !IsConnecting}"
57+
Margin="0,8,0,0"/>
58+
59+
<!-- Connecting indicator -->
60+
<TextBlock Text="Connecting..."
61+
FontSize="13" Foreground="Gray"
62+
HorizontalAlignment="Center"
63+
IsVisible="{Binding IsConnecting}"/>
64+
</StackPanel>
65+
</Border>
66+
</Grid>
67+
</UserControl>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using Avalonia.Controls;
2+
using Avalonia.Markup.Xaml;
3+
4+
namespace RequestTracker.Android.Views;
5+
6+
public partial class ConnectionDialogView : UserControl
7+
{
8+
public ConnectionDialogView()
9+
{
10+
InitializeComponent();
11+
}
12+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using System;
2+
using CommunityToolkit.Mvvm.ComponentModel;
3+
using CommunityToolkit.Mvvm.Input;
4+
5+
namespace RequestTracker.Core.ViewModels;
6+
7+
public partial class ConnectionViewModel : ViewModelBase
8+
{
9+
[ObservableProperty]
10+
private string _host = "192.168.1.100";
11+
12+
[ObservableProperty]
13+
private string _port = "5000";
14+
15+
[ObservableProperty]
16+
private string _errorMessage = "";
17+
18+
[ObservableProperty]
19+
private bool _isConnecting;
20+
21+
/// <summary>Raised when the user taps Connect with a valid URL.</summary>
22+
public event Action<string>? Connected;
23+
24+
[RelayCommand]
25+
private void Connect()
26+
{
27+
ErrorMessage = "";
28+
29+
if (string.IsNullOrWhiteSpace(Host))
30+
{
31+
ErrorMessage = "Host is required.";
32+
return;
33+
}
34+
35+
if (string.IsNullOrWhiteSpace(Port) || !int.TryParse(Port.Trim(), out var portNumber) || portNumber < 1 || portNumber > 65535)
36+
{
37+
ErrorMessage = "Port must be between 1 and 65535.";
38+
return;
39+
}
40+
41+
var url = $"http://{Host.Trim()}:{portNumber}";
42+
if (!Uri.TryCreate(url, UriKind.Absolute, out _))
43+
{
44+
ErrorMessage = "Invalid host or port.";
45+
return;
46+
}
47+
48+
IsConnecting = true;
49+
Connected?.Invoke(url);
50+
}
51+
}

src/RequestTracker.Core/ViewModels/MainWindowViewModel.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,12 @@ public MainWindowViewModel(IClipboardService clipboardService)
207207
_mcpSessionService = new McpSessionLogService(GetMcpBaseUrl());
208208
}
209209

210+
public MainWindowViewModel(IClipboardService clipboardService, string mcpBaseUrl)
211+
{
212+
_clipboardService = clipboardService;
213+
_mcpSessionService = new McpSessionLogService(mcpBaseUrl);
214+
}
215+
210216
/// <summary>Command for tree item tap (handles directory expand/collapse and MCP node refresh).</summary>
211217
[RelayCommand]
212218
private void TreeItemTapped(FileNode? node)

0 commit comments

Comments
 (0)