me-web? 0.3: the path in drawn steps, each step's checks under it, the real RAM
Build / Desktop, server and tools (push) Successful in 59s
Release / Every platform, the server, the release (push) Successful in 7m35s

- The path from this device to the internet is a vertical zig-zag of larger drawings (this
  phone or computer, the router or the mobile network, a shared exit, the provider's building,
  the globe) that pulse while their step is checked, joined by curved wires with the link and
  its speed, and a few details beside each: the model, the addresses inside and outside the
  router and which port-opening protocols answer, the AS number, the public addresses.
- The results are grouped under the step they concern, in the path's order, with the same
  drawing as a heading; tapping a step in the path scrolls to its checks.
- After a check, the status and "Check again" move to the end, beside sharing.
- Memory reads the device's RAM: on Android it showed the runtime's heap limit (0.1 GB).
  Labelled "Memory (RAM)" in every language. Free disk is read for the app's own folder, so
  Android shows it too. The device's model is read on Android, Linux and Windows.
- Two icons drew outside their box (the outside test's shield, the calls and games radio
  tower): joined Lucide elements started with a relative move. Fixed; twelve unused icons
  deleted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012CzABvBkbcFqoHdmi8b9WB
This commit is contained in:
thepraandClaude Opus 5.5 committed 2026-10-15 08:08:37 +02:00
1 parent 7cfc8b6de5
commit 37752f9f07
126 files changed
+699 -281

No files matched your search

+132 -97
View File
@@ -6,6 +6,48 @@
x:DataType="vm:MainViewModel"
FlowDirection="{Binding Flow}"
Background="{StaticResource GroundBrush}">
<UserControl.Resources>
<DataTemplate x:Key="CardTemplate" x:DataType="vm:CardViewModel">
<Border Classes="card"
Classes.good="{Binding IsGood}" Classes.caution="{Binding IsCaution}"
Classes.bad="{Binding IsBad}" Classes.unknown="{Binding IsUnknown}" Classes.info="{Binding IsInfo}">
<StackPanel Spacing="10">
<Grid ColumnDefinitions="Auto,*,Auto">
<Path Grid.Column="0" Classes="icon" Data="{Binding Icon}" VerticalAlignment="Center" />
<TextBlock Grid.Column="1" Classes="cardTitle" Text="{Binding Title}" />
<Border Grid.Column="2" Classes="chip">
<TextBlock Text="{Binding OutcomeFormatted}" />
</Border>
</Grid>
<ProgressBar Classes="thin" IsIndeterminate="True" IsVisible="{Binding ShowRunning}" />
<TextBlock Classes="summary" Text="{Binding Summary}" IsVisible="{Binding ShowSettled}" />
<ItemsControl ItemsSource="{Binding Facts}" IsVisible="{Binding ShowSettled}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:FactViewModel">
<Grid ColumnDefinitions="2*,3*" Margin="0,3">
<TextBlock Grid.Column="0" Classes="factLabel" Text="{Binding Label}" />
<StackPanel Grid.Column="1">
<SelectableTextBlock Classes="factValue" Text="{Binding Value}" IsVisible="{Binding ShowValue}" />
<Button Classes="link" Content="{Binding Source}" IsVisible="{Binding ShowSource}"
AutomationProperties.AutomationId="{Binding AutomationId}"
Command="{Binding OpenCommand}" />
<Button Classes="link" Content="{Binding Value}" IsVisible="{Binding ShowPlainLink}"
AutomationProperties.AutomationId="{Binding AutomationId}"
Command="{Binding OpenCommand}" />
</StackPanel>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Expander Classes="explain" Header="{s:Tr WhatIsThis}" IsExpanded="{Binding IsExpanded}"
AutomationProperties.AutomationId="{Binding ExplainAutomationId}">
<TextBlock Classes="body" FontSize="14" Text="{Binding Explain}" />
</Expander>
</StackPanel>
</Border>
</DataTemplate>
</UserControl.Resources>
<Grid>
<DockPanel>
<Grid DockPanel.Dock="Top" ColumnDefinitions="*,Auto,Auto" Margin="20,14,20,6">
@@ -40,7 +82,7 @@
<TextBlock Classes="small" Text="{Binding VersionFormatted}" HorizontalAlignment="Center" />
</StackPanel>
<ScrollViewer HorizontalScrollBarVisibility="Disabled">
<ScrollViewer x:Name="Scroller" HorizontalScrollBarVisibility="Disabled">
<StackPanel Spacing="26" Margin="8,4,8,24">
<Border Classes="banner" IsVisible="{Binding ShowUpdate}">
<StackPanel Orientation="Horizontal" Spacing="12">
@@ -51,7 +93,7 @@
</StackPanel>
</Border>
<StackPanel Spacing="16" HorizontalAlignment="Center" MaxWidth="600" Margin="8,6,8,0">
<StackPanel Spacing="16" HorizontalAlignment="Center" MaxWidth="600" Margin="8,6,8,0" IsVisible="{Binding !HasResults}">
<Grid Width="120" Height="120" HorizontalAlignment="Center">
<Ellipse Classes="pulse" Width="120" Height="120" IsVisible="{Binding ShowChecking}" />
<Ellipse Width="96" Height="96" Fill="{StaticResource SurfaceRaisedBrush}" Stroke="{StaticResource LineBrush}" StrokeThickness="2" />
@@ -67,61 +109,51 @@
Command="{Binding CheckCommand}" />
</StackPanel>
<StackPanel Spacing="14" IsVisible="{Binding HasResults}">
<StackPanel Spacing="6" IsVisible="{Binding HasResults}">
<TextBlock Classes="section" Text="{s:Tr PathTitle}" HorizontalAlignment="Center" />
<ItemsControl ItemsSource="{Binding Path}" IsVisible="{Binding IsWide}" HorizontalAlignment="Center">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:PathNodeViewModel">
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
<Grid Width="56" Height="64" VerticalAlignment="Top" IsVisible="{Binding ShowConnector}">
<TextBlock Classes="linkLabel" Text="{Binding LinkLabel}" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,6,0,0" />
<Line StartPoint="4,32" EndPoint="52,32" Classes="connector" Classes.flowing="{Binding IsRunning}" Classes.lit="{Binding IsLit}" />
</Grid>
<StackPanel Width="124" Spacing="6" Classes="node" Classes.lit="{Binding IsLit}"
AutomationProperties.AutomationId="{Binding AutomationId}">
<Grid Width="64" Height="64" HorizontalAlignment="Center">
<Ellipse Classes="pulse" Width="64" Height="64" IsVisible="{Binding IsRunning}" />
<Ellipse Classes="disc" Width="64" Height="64"
Classes.good="{Binding IsGood}" Classes.caution="{Binding IsCaution}"
Classes.bad="{Binding IsBad}" Classes.unknown="{Binding IsUnknown}" />
<Viewbox Width="28" Height="28">
<Path Classes="icon" Data="{Binding Icon}" />
</Viewbox>
</Grid>
<TextBlock Classes="nodeTitle" Text="{Binding Title}" TextAlignment="Center" />
<TextBlock Classes="nodeSubtitle" Text="{Binding Subtitle}" TextAlignment="Center" />
</StackPanel>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl ItemsSource="{Binding Path}" IsVisible="{Binding IsNarrow}" HorizontalAlignment="Center" MinWidth="280" Margin="16,0">
<ItemsControl ItemsSource="{Binding Path}" MaxWidth="580" Margin="16,8,16,0">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:PathNodeViewModel">
<StackPanel>
<Grid Height="36" ColumnDefinitions="64,*" IsVisible="{Binding ShowConnector}">
<Line Grid.Column="0" StartPoint="32,2" EndPoint="32,34" Classes="connector" Classes.flowing="{Binding IsRunning}" Classes.lit="{Binding IsLit}" />
<TextBlock Grid.Column="1" Classes="linkLabel" Text="{Binding LinkLabel}" VerticalAlignment="Center" Margin="8,0,0,0" />
<Grid Height="62" Margin="45,0" IsVisible="{Binding ShowConnector}">
<Path Classes="wire" Data="{StaticResource WireToEnd}" IsVisible="{Binding WireToEnd}"
Classes.flowing="{Binding IsRunning}" Classes.lit="{Binding IsLit}" />
<Path Classes="wire" Data="{StaticResource WireToStart}" IsVisible="{Binding WireToStart}"
Classes.flowing="{Binding IsRunning}" Classes.lit="{Binding IsLit}" />
<Border Classes="linkTag" IsVisible="{Binding ShowLink}">
<StackPanel Orientation="Horizontal" Spacing="6">
<Viewbox Width="15" Height="15">
<Path Classes="icon" Data="{Binding LinkIcon}" />
</Viewbox>
<TextBlock Classes="linkLabel" Text="{Binding LinkLabel}" VerticalAlignment="Center" />
</StackPanel>
</Border>
</Grid>
<Grid ColumnDefinitions="64,*" Classes="node" Classes.lit="{Binding IsLit}"
AutomationProperties.AutomationId="{Binding AutomationId}">
<Grid Grid.Column="0" Width="56" Height="56">
<Ellipse Classes="pulse" Width="56" Height="56" IsVisible="{Binding IsRunning}" />
<Ellipse Classes="disc" Width="56" Height="56"
Classes.good="{Binding IsGood}" Classes.caution="{Binding IsCaution}"
Classes.bad="{Binding IsBad}" Classes.unknown="{Binding IsUnknown}" />
<Viewbox Width="24" Height="24">
<Path Classes="icon" Data="{Binding Icon}" />
</Viewbox>
</Grid>
<StackPanel Grid.Column="1" VerticalAlignment="Center" Margin="12,0,0,0" Spacing="2">
<TextBlock Classes="nodeTitle" Text="{Binding Title}" />
<TextBlock Classes="nodeSubtitle" Text="{Binding Subtitle}" />
<Grid ColumnDefinitions="Auto,*,Auto">
<Button Grid.Column="{Binding ArtColumn}" Classes="hop" Click="OnHop"
AutomationProperties.AutomationId="{Binding AutomationId}"
AutomationProperties.Name="{Binding Title}">
<Grid Width="90" Height="90" Classes="node" Classes.lit="{Binding IsLit}">
<Ellipse Classes="pulse" Width="90" Height="90" IsVisible="{Binding IsRunning}" />
<Ellipse Classes="disc" Width="90" Height="90"
Classes.good="{Binding IsGood}" Classes.caution="{Binding IsCaution}"
Classes.bad="{Binding IsBad}" Classes.unknown="{Binding IsUnknown}" />
<Viewbox Width="58" Height="58">
<Grid Classes="art" Width="48" Height="48" Classes.running="{Binding IsRunning}"
Classes.good="{Binding IsGood}" Classes.caution="{Binding IsCaution}"
Classes.bad="{Binding IsBad}" Classes.unknown="{Binding IsUnknown}">
<Path Classes="art" Data="{Binding ArtBase}" />
<Path Classes="art beat b1" Data="{Binding ArtBeat1}" />
<Path Classes="art beat b2" Data="{Binding ArtBeat2}" />
<Path Classes="art beat b3" Data="{Binding ArtBeat3}" />
<Path Classes="art beat spin" Data="{Binding ArtSpin}" />
</Grid>
</Viewbox>
</Grid>
</Button>
<StackPanel Grid.Column="1" Classes="hopText" Classes.lit="{Binding IsLit}" VerticalAlignment="Center" Margin="16,0" Spacing="4">
<TextBlock Classes="hopTitle" Text="{Binding Title}" TextAlignment="{Binding TextSide}" />
<TextBlock Classes="hopDetail" Text="{Binding DetailsFormatted}" TextAlignment="{Binding TextSide}" IsVisible="{Binding ShowDetails}" />
</StackPanel>
</Grid>
</StackPanel>
@@ -130,7 +162,6 @@
</ItemsControl>
</StackPanel>
<Border Classes="consent" IsVisible="{Binding AskReach}" MaxWidth="760">
<StackPanel Spacing="10">
<TextBlock Classes="section" Margin="0" Text="{s:Tr ReachAskTitle}" />
@@ -180,53 +211,40 @@
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
<StackPanel Spacing="8" IsVisible="{Binding HasResults}">
<StackPanel Spacing="4" IsVisible="{Binding HasResults}">
<TextBlock Classes="section" Text="{s:Tr ResultsTitle}" HorizontalAlignment="Center" />
<ItemsControl ItemsSource="{Binding Cards}" HorizontalAlignment="Center">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel ItemWidth="{Binding CardWidth}" HorizontalAlignment="Center" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl x:Name="Groups" ItemsSource="{Binding Path}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:CardViewModel">
<Border Classes="card"
Classes.good="{Binding IsGood}" Classes.caution="{Binding IsCaution}"
Classes.bad="{Binding IsBad}" Classes.unknown="{Binding IsUnknown}" Classes.info="{Binding IsInfo}">
<StackPanel Spacing="10">
<Grid ColumnDefinitions="Auto,*,Auto">
<Path Grid.Column="0" Classes="icon" Data="{Binding Icon}" VerticalAlignment="Center" />
<TextBlock Grid.Column="1" Classes="cardTitle" Text="{Binding Title}" />
<Border Grid.Column="2" Classes="chip">
<TextBlock Text="{Binding OutcomeFormatted}" />
</Border>
<DataTemplate x:DataType="vm:PathNodeViewModel">
<StackPanel Spacing="2" Margin="0,16,0,0">
<Grid ColumnDefinitions="Auto,Auto,*" Margin="16,0">
<Grid Width="46" Height="46">
<Ellipse Classes="disc thin" Width="46" Height="46"
Classes.good="{Binding IsGood}" Classes.caution="{Binding IsCaution}"
Classes.bad="{Binding IsBad}" Classes.unknown="{Binding IsUnknown}" />
<Viewbox Width="30" Height="30">
<Grid Classes="art" Width="48" Height="48"
Classes.good="{Binding IsGood}" Classes.caution="{Binding IsCaution}"
Classes.bad="{Binding IsBad}" Classes.unknown="{Binding IsUnknown}">
<Path Classes="art" Data="{Binding ArtBase}" />
<Path Classes="art beat b1" Data="{Binding ArtBeat1}" />
<Path Classes="art beat b2" Data="{Binding ArtBeat2}" />
<Path Classes="art beat b3" Data="{Binding ArtBeat3}" />
<Path Classes="art beat spin" Data="{Binding ArtSpin}" />
</Grid>
</Viewbox>
</Grid>
<ProgressBar Classes="thin" IsIndeterminate="True" IsVisible="{Binding ShowRunning}" />
<TextBlock Classes="summary" Text="{Binding Summary}" IsVisible="{Binding ShowSettled}" />
<ItemsControl ItemsSource="{Binding Facts}" IsVisible="{Binding ShowSettled}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:FactViewModel">
<Grid ColumnDefinitions="2*,3*" Margin="0,3">
<TextBlock Grid.Column="0" Classes="factLabel" Text="{Binding Label}" />
<StackPanel Grid.Column="1">
<SelectableTextBlock Classes="factValue" Text="{Binding Value}" IsVisible="{Binding ShowValue}" />
<Button Classes="link" Content="{Binding Source}" IsVisible="{Binding ShowSource}"
AutomationProperties.AutomationId="{Binding AutomationId}"
Command="{Binding OpenCommand}" />
<Button Classes="link" Content="{Binding Value}" IsVisible="{Binding ShowPlainLink}"
AutomationProperties.AutomationId="{Binding AutomationId}"
Command="{Binding OpenCommand}" />
</StackPanel>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Expander Classes="explain" Header="{s:Tr WhatIsThis}" IsExpanded="{Binding IsExpanded}"
AutomationProperties.AutomationId="{Binding ExplainAutomationId}">
<TextBlock Classes="body" FontSize="14" Text="{Binding Explain}" />
</Expander>
</StackPanel>
</Border>
<TextBlock Grid.Column="1" Classes="groupTitle" Text="{Binding Title}" VerticalAlignment="Center" Margin="12,0" />
<Rectangle Grid.Column="2" Classes="rule" VerticalAlignment="Center" />
</Grid>
<ItemsControl ItemsSource="{Binding Cards}" ItemTemplate="{StaticResource CardTemplate}" HorizontalAlignment="Center">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel ItemWidth="{Binding $parent[UserControl].((vm:MainViewModel)DataContext).CardWidth}" HorizontalAlignment="Center" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
@@ -247,6 +265,23 @@
<TextBlock Classes="body" TextAlignment="Center" HorizontalAlignment="Center" MaxWidth="700"
Text="{Binding ShareResult}" IsVisible="{Binding ShowShareResult}" />
<StackPanel Spacing="16" HorizontalAlignment="Center" MaxWidth="600" Margin="8,4,8,0" IsVisible="{Binding HasResults}">
<Grid ColumnDefinitions="Auto,*" HorizontalAlignment="Center">
<Grid Width="64" Height="64">
<Ellipse Classes="pulse" Width="64" Height="64" IsVisible="{Binding ShowChecking}" />
<Ellipse Width="52" Height="52" Fill="{StaticResource SurfaceRaisedBrush}" Stroke="{StaticResource LineBrush}" StrokeThickness="2" />
<Ellipse Width="28" Height="28" Fill="{StaticResource GoodBrush}" IsVisible="{Binding ShowOnline}" />
<Ellipse Width="28" Height="28" Fill="{StaticResource CautionBrush}" IsVisible="{Binding ShowCaptive}" />
<Ellipse Width="28" Height="28" Fill="{StaticResource BadBrush}" IsVisible="{Binding ShowOffline}" />
<Ellipse Width="28" Height="28" Fill="{StaticResource TextSoftBrush}" Opacity="0.4" IsVisible="{Binding ShowChecking}" />
</Grid>
<TextBlock Grid.Column="1" Classes="status" Text="{Binding StatusFormatted}" VerticalAlignment="Center" TextAlignment="Start" Margin="14,0,0,0" />
</Grid>
<Button Classes="primary" Content="{Binding CheckFormatted}"
AutomationProperties.AutomationId="main-check-again"
Command="{Binding CheckCommand}" />
</StackPanel>
<StackPanel Spacing="12" HorizontalAlignment="Center" Margin="8,10,8,0">
<TextBlock Classes="section" Text="{s:Tr ElsewhereTitle}" HorizontalAlignment="Center" />
<TextBlock Classes="small" Text="{s:Tr ElsewhereBody}" HorizontalAlignment="Center" TextAlignment="Center" MaxWidth="560" />
+29 -2
View File
@@ -1,3 +1,5 @@
using System.ComponentModel;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
@@ -8,12 +10,16 @@ namespace MeWeb.App.Views;
public partial class MainView : UserControl
{
MainViewModel model;
public MainView() => InitializeComponent();
protected override void OnLoaded(RoutedEventArgs e)
{
base.OnLoaded(e);
if (DataContext is not MainViewModel model) return;
if (DataContext is not MainViewModel loaded) return;
model = loaded;
model.PropertyChanged += OnModelChanged;
model.Launcher = TopLevel.GetTopLevel(this)?.Launcher;
model.Clipboard = TopLevel.GetTopLevel(this)?.Clipboard;
_ = model.CleanLeftovers();
@@ -21,9 +27,30 @@ public partial class MainView : UserControl
model.StartCommand.Execute(null);
}
protected override void OnUnloaded(RoutedEventArgs e)
{
if (model is not null) model.PropertyChanged -= OnModelChanged;
model = null;
base.OnUnloaded(e);
}
protected override void OnSizeChanged(SizeChangedEventArgs e)
{
base.OnSizeChanged(e);
if (DataContext is MainViewModel model) model.AvailableWidth = e.NewSize.Width;
if (DataContext is MainViewModel sized) sized.AvailableWidth = e.NewSize.Width;
}
void OnModelChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(MainViewModel.IsChecking) && model?.IsChecking == true) Scroller.ScrollToHome();
}
void OnHop(object sender, RoutedEventArgs e)
{
if (sender is not Control { DataContext: PathNodeViewModel node }) return;
if (Groups.ContainerFromItem(node) is not Control group || Scroller.Content is not Visual content) return;
var at = group.TranslatePoint(default, content);
if (at is null) return;
Scroller.Offset = new Vector(Scroller.Offset.X, Math.Max(0, at.Value.Y - 8));
}
}