Public Access
230 lines
13 KiB
XML
230 lines
13 KiB
XML
<UserControl xmlns="https://github.com/avaloniaui"
|
||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||
xmlns:vm="using:DodoSSH.Client.Shell.ViewModels"
|
||
x:Class="DodoSSH.Client.Android.Views.PhoneRail"
|
||
x:DataType="vm:MainWindowViewModel">
|
||
|
||
<!--
|
||
◆ The destinations down the left edge, on a surface too wide to be a phone.
|
||
|
||
This is the desktop head's NavRail arrangement rather than a second design: a column of destinations at
|
||
the left, each a glyph and a word, the current one lit. What it is not is that head's *file* — the two
|
||
heads cannot share a view, and this one draws the phone's destination set with the phone's palette and
|
||
the phone's touch targets.
|
||
|
||
── WHY IT EXISTS AT ALL ────────────────────────────────────────────────────────────────────────────────
|
||
The bottom bar carries three entries and everything else lives one tap deeper behind SETTINGS. That is
|
||
the right shape at 360dp, where a fourth entry costs the width of the three that are there. It is the
|
||
wrong shape on a tablet or an unfolded foldable, where there is room for every destination at once and
|
||
the hub becomes an extra tap between the user and a screen they can already see space for.
|
||
|
||
So above the breakpoint the bar stands down and this takes its place, with all nine destinations that
|
||
were split between the bar and the hub. SETTINGS is not among them: it is a list of the things on this
|
||
rail, and a rail entry leading to a menu of the rail would be furniture.
|
||
|
||
── WHAT IT SHOWS THAT THE HUB DID NOT ──────────────────────────────────────────────────────────────────
|
||
A count beside Hosts and Keychain, which is what the desktop rail's extra width buys there too. Only
|
||
where a count is real: Logs has no total until it is read and Preferences is not a quantity, so those
|
||
show nothing rather than a zero — a number the application never computed is worse than a blank.
|
||
|
||
── SFTP AND S3 ARE HERE, WHERE THE DESKTOP PUTS THEM IN ITS TAB STRIP ──────────────────────────────────
|
||
That head has fixed tabs for the two destinations that are not about the keychain; this one has no tab
|
||
strip, and its hub already listed them beside the rest. Putting them anywhere else would be inventing a
|
||
third arrangement for one screen's worth of difference.
|
||
|
||
── STYLES ARE LOCAL, COLOURS ARE NOT ───────────────────────────────────────────────────────────────────
|
||
The .railentry styles live in this file because they are this control's own shape and nothing else wears
|
||
them; every colour in them is resolved from Theme/Palette.axaml by key, which is the rule that matters —
|
||
a rail that named its own blues is how a fifth surface colour ends up in the application.
|
||
|
||
── DEEP CHROME, SINCE v5 ───────────────────────────────────────────────────────────────────────────────
|
||
This rail's own surface moves from Sidebar to DeepChrome in this pass, matching the desktop's NavRail —
|
||
which is exactly what this control is standing in for on a wide phone, and which took the same v5b move
|
||
itself: Palette.axaml's own remark on DeepChrome names "the rail down the side" as one of the five things
|
||
that colour is for. Sidebar stays what a card sits on; this is the frame the cards sit inside, the same
|
||
distinction PhoneShell's header, strip and bottom bar are drawing at the same time.
|
||
|
||
The hover fill moves too, from Panel to Track — and Track rather than Hover, because Palette.axaml's own
|
||
remark on Track names "the rail row a pointer sits over" as one of the three things that colour is for,
|
||
literally. Panel was never named for this; it read close enough that nobody had gone looking for the
|
||
seam, which is exactly the kind of gap Track exists to close.
|
||
-->
|
||
|
||
<UserControl.Styles>
|
||
<Style Selector="Button.railentry">
|
||
<Setter Property="Background" Value="Transparent" />
|
||
<Setter Property="BorderThickness" Value="0" />
|
||
<Setter Property="CornerRadius" Value="10" />
|
||
<Setter Property="Padding" Value="12,0" />
|
||
|
||
<!-- 48, not the bar's 64: a rail entry is a row rather than a target at the screen's edge, and nine
|
||
of them at 64 would not fit the shortest surface this layout is drawn on. Still above the 44
|
||
every other touch target here is held to. -->
|
||
<Setter Property="MinHeight" Value="48" />
|
||
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
||
</Style>
|
||
|
||
<Style Selector="Button.railentry:pointerover /template/ ContentPresenter">
|
||
<Setter Property="Background" Value="{StaticResource Track}" />
|
||
</Style>
|
||
|
||
<Style Selector="Button.railentry.active /template/ ContentPresenter">
|
||
<Setter Property="Background" Value="{StaticResource Active}" />
|
||
</Style>
|
||
|
||
<Style Selector="Button.railentry TextBlock.railglyph">
|
||
<Setter Property="Foreground" Value="{StaticResource TextDim}" />
|
||
<Setter Property="FontSize" Value="14" />
|
||
<Setter Property="Width" Value="24" />
|
||
<Setter Property="VerticalAlignment" Value="Center" />
|
||
</Style>
|
||
|
||
<Style Selector="Button.railentry TextBlock.raillabel">
|
||
<Setter Property="Foreground" Value="{StaticResource TextDim}" />
|
||
<Setter Property="FontFamily" Value="{StaticResource MonoFont}" />
|
||
<Setter Property="FontSize" Value="12.5" />
|
||
<Setter Property="VerticalAlignment" Value="Center" />
|
||
<Setter Property="TextTrimming" Value="CharacterEllipsis" />
|
||
</Style>
|
||
|
||
<Style Selector="Button.railentry TextBlock.railcount">
|
||
<Setter Property="Foreground" Value="{StaticResource TextFaint}" />
|
||
<Setter Property="FontFamily" Value="{StaticResource MonoFont}" />
|
||
<Setter Property="FontSize" Value="10.5" />
|
||
<Setter Property="VerticalAlignment" Value="Center" />
|
||
</Style>
|
||
|
||
<!-- Three signals for the current entry rather than one, which is the rule NavButton already states for
|
||
the bar it replaces: colour alone at this size is what a user with a colour deficiency is left
|
||
with. Here it is the filled row, the accent, and the weight. -->
|
||
<Style Selector="Button.railentry.active TextBlock.railglyph">
|
||
<Setter Property="Foreground" Value="{StaticResource AccentText}" />
|
||
</Style>
|
||
|
||
<Style Selector="Button.railentry.active TextBlock.raillabel">
|
||
<Setter Property="Foreground" Value="{StaticResource AccentText}" />
|
||
<Setter Property="FontWeight" Value="SemiBold" />
|
||
</Style>
|
||
</UserControl.Styles>
|
||
|
||
<Border Width="188" Background="{StaticResource DeepChrome}"
|
||
BorderBrush="{StaticResource Border}" BorderThickness="0,0,1,0">
|
||
|
||
<!--
|
||
DockPanel with LastChildFill false, exactly as the desktop rail does it: Preferences is pinned to the
|
||
foot because it is the one entry about the machine rather than about the keychain, and everything else
|
||
flows from the top. A ScrollViewer over the top group so that a short surface — a foldable's cover
|
||
display, a small window in Android's freeform mode — scrolls the list rather than clipping it.
|
||
-->
|
||
<DockPanel LastChildFill="False">
|
||
|
||
<StackPanel DockPanel.Dock="Bottom" Margin="8,0,8,10">
|
||
<Button Classes="railentry" Classes.active="{Binding IsPreferencesShowing}"
|
||
Command="{Binding ShowScreenCommand}"
|
||
CommandParameter="{x:Static vm:ShellScreen.Preferences}">
|
||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||
<TextBlock Grid.Column="0" Classes="railglyph" Text="⚙" />
|
||
<TextBlock Grid.Column="1" Classes="raillabel" Text="Preferences" />
|
||
</Grid>
|
||
</Button>
|
||
</StackPanel>
|
||
|
||
<ScrollViewer DockPanel.Dock="Top" VerticalScrollBarVisibility="Auto"
|
||
HorizontalScrollBarVisibility="Disabled">
|
||
<StackPanel Margin="8,10,8,0" Spacing="2">
|
||
|
||
<Button Classes="railentry" Classes.active="{Binding IsHostsShowing}"
|
||
Command="{Binding ShowScreenCommand}"
|
||
CommandParameter="{x:Static vm:ShellScreen.Hosts}">
|
||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||
<TextBlock Grid.Column="0" Classes="railglyph" Text="▤" />
|
||
<TextBlock Grid.Column="1" Classes="raillabel" Text="Hosts" />
|
||
<TextBlock Grid.Column="2" Classes="railcount" Text="{Binding Vault.Hosts.Count}" />
|
||
</Grid>
|
||
</Button>
|
||
|
||
<!--
|
||
The terminal is a surface rather than a page, so it goes through its own command — the same
|
||
reason the bottom bar's middle entry does. It lights on IsTerminalSurface, which on this control
|
||
can only mean one thing: the rail stands down for a shell, so the one moment it is drawn beside
|
||
this surface is Connections with nothing running. That screen is a page in everything but which
|
||
enum it is in, and a rail sitting beside it with no entry lit would be pointing nowhere.
|
||
|
||
No count, unlike the two above it. The shells strip sits above the bottom of every page on this
|
||
surface and is that count, drawn as the sessions themselves — a number beside this word would be
|
||
the same fact said twice, three inches apart.
|
||
-->
|
||
<Button Classes="railentry" Classes.active="{Binding IsTerminalSurface}"
|
||
Command="{Binding ShowTerminalCommand}">
|
||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||
<TextBlock Grid.Column="0" Classes="railglyph" Text="⌗" />
|
||
<TextBlock Grid.Column="1" Classes="raillabel" Text="Connections" />
|
||
</Grid>
|
||
</Button>
|
||
|
||
<Border Height="1" Background="{StaticResource Border}" Margin="4,8" />
|
||
|
||
<Button Classes="railentry" Classes.active="{Binding IsKeychainShowing}"
|
||
Command="{Binding ShowScreenCommand}"
|
||
CommandParameter="{x:Static vm:ShellScreen.Keychain}">
|
||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||
<TextBlock Grid.Column="0" Classes="railglyph" Text="⚿" />
|
||
<TextBlock Grid.Column="1" Classes="raillabel" Text="Keychain" />
|
||
<TextBlock Grid.Column="2" Classes="railcount" Text="{Binding Vault.Keys.Count}" />
|
||
</Grid>
|
||
</Button>
|
||
|
||
<Button Classes="railentry" Classes.active="{Binding IsSnippetsShowing}"
|
||
Command="{Binding ShowScreenCommand}"
|
||
CommandParameter="{x:Static vm:ShellScreen.Snippets}">
|
||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||
<TextBlock Grid.Column="0" Classes="railglyph" Text="❯" />
|
||
<TextBlock Grid.Column="1" Classes="raillabel" Text="Snippets" />
|
||
</Grid>
|
||
</Button>
|
||
|
||
<Button Classes="railentry" Classes.active="{Binding IsTransfersShowing}"
|
||
Command="{Binding ShowFilesCommand}"
|
||
CommandParameter="{x:Static vm:RemoteKind.Host}">
|
||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||
<TextBlock Grid.Column="0" Classes="railglyph" Text="⇅" />
|
||
<TextBlock Grid.Column="1" Classes="raillabel" Text="SFTP" />
|
||
</Grid>
|
||
</Button>
|
||
|
||
<Button Classes="railentry" Classes.active="{Binding IsBucketsShowing}"
|
||
Command="{Binding ShowFilesCommand}"
|
||
CommandParameter="{x:Static vm:RemoteKind.Bucket}">
|
||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||
<TextBlock Grid.Column="0" Classes="railglyph" Text="◳" />
|
||
<TextBlock Grid.Column="1" Classes="raillabel" Text="S3" />
|
||
</Grid>
|
||
</Button>
|
||
|
||
<Button Classes="railentry" Classes.active="{Binding IsLogsShowing}"
|
||
Command="{Binding ShowScreenCommand}"
|
||
CommandParameter="{x:Static vm:ShellScreen.Logs}">
|
||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||
<TextBlock Grid.Column="0" Classes="railglyph" Text="≡" />
|
||
<TextBlock Grid.Column="1" Classes="raillabel" Text="Logs" />
|
||
</Grid>
|
||
</Button>
|
||
|
||
<Button Classes="railentry" Classes.active="{Binding IsVaultsShowing}"
|
||
Command="{Binding ShowScreenCommand}"
|
||
CommandParameter="{x:Static vm:ShellScreen.Vaults}">
|
||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||
<TextBlock Grid.Column="0" Classes="railglyph" Text="◎" />
|
||
<TextBlock Grid.Column="1" Classes="raillabel" Text="Vaults" />
|
||
</Grid>
|
||
</Button>
|
||
|
||
</StackPanel>
|
||
</ScrollViewer>
|
||
|
||
</DockPanel>
|
||
</Border>
|
||
|
||
</UserControl>
|