<UserControl xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:vm="using:DodoSSH.Client.Shell.ViewModels"
             xmlns:views="using:DodoSSH.Client.Android.Views"
             x:Class="DodoSSH.Client.Android.Views.PhoneShell"
             x:DataType="vm:MainWindowViewModel"
             Background="{StaticResource Canvas}">

  <!--
    The phone's single view, and the counterpart of the desktop head's MainWindow — except that this one has
    no window, no nav rail, no titlebar and no status bar.

    It switches on ShellState, which is the same six states the desktop has because both heads share one
    state machine. What differs is only what each one draws.

    ── v2 ────────────────────────────────────────────────────────────────────────────────────────────────
    The desktop's eight rail destinations become four in a bottom bar, and the rest live one tap deeper
    behind MORE: snippets, SFTP, S3, logs, preferences — and teams, which v2 did not draw and which is
    argued for on the screen itself. That is the v2 design's own arrangement, and it replaces the first
    design's four, which had nothing behind them at all. Five characters was a desktop constraint and the
    phone uses words.

    The order is the design's rather than the rail's. Terminal sits second, beside Hosts, because those two
    are the pair a session moves between; on the desktop the terminal is not a rail entry at all.

    ── a terminal gets the screen ─────────────────────────────────────────────────────────────────────────
    Three of the four rows below stand down while a shell is showing: the header, the shells strip and the
    bottom bar itself. All three are bound on IsShowingPages, which is the same question asked once — the
    surface is either a page or a terminal, and these are the chrome a page has.

    The arithmetic is why. Header 56, strip 46, bar 64, and the terminal's own two rows on top of that: at
    360dp the shell was framed by about a third of the display, all of it about somewhere the user was not.
    What takes their place is one 35-pixel bar drawn by the surface itself, carrying back on the left and
    the sessions and a + across from it. See TerminalScreen.axaml.
  -->

  <!--
    Named, and the name is load-bearing: everything the phone draws is inside this one element, so its
    bottom margin is the single place the software keyboard can be kept off the box being typed into,
    whichever of the eleven screens is showing. See PhoneShell.axaml.cs.
  -->
  <Panel x:Name="Body">

    <!-- ============ getting in ============ -->
    <views:PendingScreen IsVisible="{Binding IsStarting}"
                         Heading="OPENING THE KEYCHAIN"
                         Detail="Reading this phone's local cache to find out whether it is enrolled." />

    <views:ServerScreen IsVisible="{Binding IsNeedingServer}" />
    <views:EnrollScreen IsVisible="{Binding IsNeedingEnrollment}" />
    <views:RecoveryCodeScreen IsVisible="{Binding IsShowingRecoveryCode}" />
    <views:LockedScreen IsVisible="{Binding IsLocked}" />

    <!-- ============ unlocked ============ -->
    <Grid IsVisible="{Binding IsUnlocked}" RowDefinitions="Auto,*,Auto,Auto">

      <!--
        The header: which vault, and whether it is synced.

        Hidden behind MORE, and that is the design's arrangement rather than a saving. v2 gives every screen
        one header carrying that screen's own name and its own actions — a back arrow, an add, a refresh —
        so the hub's screens draw their own and this one stands down rather than stacking a second row of
        chrome above theirs. It stays on the two destinations that are the product's top level, where the
        vault's name and the sync light are the most useful thing a header could say.

        Wrapped rather than given a second condition, because Avalonia's bindings have no "and": the wrapper
        collapses it over a terminal, where the surface draws its own bar and the vault's name is not what
        the user is looking at. That is one of three rows this Grid stands down while a shell is showing —
        see the strip and the bottom bar below.
      -->
      <Panel Grid.Row="0" IsVisible="{Binding IsShowingPages}">
        <Border Background="{StaticResource Chrome}" BorderBrush="{StaticResource Border}"
                BorderThickness="0,0,0,1" Padding="14,0" Height="56"
                IsVisible="{Binding !IsMoreSurface}">
          <Grid ColumnDefinitions="Auto,*,Auto,Auto">

            <!--
              Filled rather than outlined since v2. The mark is the one thing on this header that is not a
              fact about the vault, and the design gives it the accent as a solid tile — which is also what
              the launcher icon draws, so the two agree.
            -->
            <Border Grid.Column="0" Width="26" Height="26" CornerRadius="8"
                    Background="{StaticResource Accent}" VerticalAlignment="Center">
              <TextBlock Text="&gt;_" Foreground="{StaticResource AccentInk}"
                         FontFamily="{StaticResource MonoFont}" FontSize="10" FontWeight="Bold"
                         HorizontalAlignment="Center" VerticalAlignment="Center" />
            </Border>

            <TextBlock Grid.Column="1" Classes="heading" Margin="10,0,8,0" FontSize="16"
                       Text="{Binding Vault.VaultName}" TextTrimming="CharacterEllipsis" />

            <!--
              The sync light, and it is green only when it has earned it — see SyncLabel. The design draws
              a permanently green "Synced" here, which is the one claim on that mock-up this application
              will not make.
            -->
            <StackPanel Grid.Column="2" Orientation="Horizontal" Spacing="6" VerticalAlignment="Center">
              <Ellipse Classes="dot" Classes.live="{Binding IsFullySynced}" Width="6" Height="6"
                       VerticalAlignment="Center" />
              <TextBlock Classes="label" FontSize="9" Text="{Binding SyncLabel}" />
            </StackPanel>

            <Button Grid.Column="3" Classes="icon" Margin="4,0,0,0" Command="{Binding LockCommand}"
                    ToolTip.Tip="Lock the keychain">
              <TextBlock Text="LOCK" Classes="label" FontSize="8.5"
                         Foreground="{StaticResource TextDim}" />
            </Button>
          </Grid>
        </Border>
      </Panel>

      <!-- The screens. Only one draws; which one is the shell's business. -->
      <Panel Grid.Row="1">
        <!--
          Wrapped rather than bound directly, and the desktop head's MainWindow carries the same note for
          the same reason: this element's visibility is the shell's business and its data context is the
          vault, and putting both on one element resolves IsVisible against the vault — where
          IsHostsShowing does not exist. It is a compile error here rather than a silent blank screen only
          because compiled bindings are on.
        -->
        <Panel IsVisible="{Binding IsHostsShowing}">
          <views:HostsScreen DataContext="{Binding Vault}" />
        </Panel>
        <Panel IsVisible="{Binding IsVaultShowing}">
          <views:KeychainScreen DataContext="{Binding Vault}" />
        </Panel>
        <!--
          IsTerminalSurface rather than IsTerminalShowing: a tab exists from the moment connecting starts and
          its session does not, so this screen has to be on show while there is nothing to render — it is
          what says which machine is being connected to. Which of the two things inside it draws is decided
          in the screen itself. See TerminalTabViewModel.
        -->
        <views:TerminalScreen IsVisible="{Binding IsTerminalSurface}" />

        <!--
          ============ under MORE ============

          The hub itself takes the shell as its data context, because every row on it is a navigation
          command; the destinations behind it each take the view model they are about, so each one is
          wrapped. SnippetsScreen and LogsScreen are nullable on the shell — they are rebuilt on every
          unlock and nulled on lock — and it is the collapsed wrapper that keeps a template from binding
          against nothing.
        -->
        <views:MoreScreen IsVisible="{Binding IsMoreShowing}" />

        <Panel IsVisible="{Binding IsSnippetsShowing}">
          <views:SnippetsScreen DataContext="{Binding SnippetsScreen}" />
        </Panel>

        <Panel IsVisible="{Binding IsLogsShowing}">
          <views:LogsScreen DataContext="{Binding LogsScreen}" />
        </Panel>

        <!--
          The sixth destination behind MORE, and the one v2 never drew — see the comment on the screen
          itself. Wrapped like its neighbours even though Teams is not nullable: the reason for the wrapper
          is the data context, not the null. IsTeamShowing is the shell's and Teams is not the shell.
        -->
        <Panel IsVisible="{Binding IsTeamShowing}">
          <views:TeamsScreen DataContext="{Binding Teams}" />
        </Panel>

        <!--
          One screen for both file destinations. SFTP and S3 differ in which picker they offer and in
          nothing else below it — the panes, the queue and the transfers are the same IRemoteFileStore
          either way — so drawing them twice would be two copies of a screen that has to stay identical.
          Which picker shows is TransfersViewModel.Remote, set on arrival by the shell.
        -->
        <Panel IsVisible="{Binding IsTransfersShowing}">
          <views:FilesScreen DataContext="{Binding Transfers}" />
        </Panel>
        <Panel IsVisible="{Binding IsBucketsShowing}">
          <views:FilesScreen DataContext="{Binding Transfers}" />
        </Panel>

        <!--
          Preferences keeps PendingScreen for its body — it is still a screen that states what is absent
          rather than one with settings on it — and gains the header its siblings under MORE have, here
          rather than inside PendingScreen: that control is shared with three states of getting in, none of
          which has anywhere to go back to.
        -->
        <Grid IsVisible="{Binding IsPreferencesShowing}" RowDefinitions="Auto,*">
          <Grid Grid.Row="0" ColumnDefinitions="Auto,*" Height="56" Margin="8,0">
            <Button Grid.Column="0" Classes="icon" Content="←" Command="{Binding ShowScreenCommand}"
                    CommandParameter="{x:Static vm:ShellScreen.More}" />
            <TextBlock Grid.Column="1" Classes="heading" Text="Preferences" Margin="4,0" />
          </Grid>
          <views:PendingScreen Grid.Row="1"
                               Heading="PREFERENCES"
                               Detail="Registering this phone's device key, and signing out, are on the unlock screen for now. Importing an ~/.ssh/config has no meaning here — scoped storage means there is no such file to read." />
        </Grid>
      </Panel>

      <!--
        ◆ The two host-key decisions, over everything. Outside the screen Panel deliberately: file transfer
        makes its own trust decision on the desktop, and the phone now has that screen — so a sheet nested
        inside the hosts screen would be one the files screen could not raise.
      -->
      <Panel Grid.Row="1">
        <views:HostKeySheet DataContext="{Binding Vault}" />
      </Panel>

      <!--
        The shells strip. The design puts it above the nav on every screen, and that is the single most
        desktop-shaped idea in the product — it is what makes a terminal a surface you switch to rather than
        a screen you navigate away from. Kept, because losing it would make an open shell invisible from the
        host list, which is where you are when you open the next one.

        v2 draws the sessions as pills rather than as a labelled row, and drops the word SHELLS: with a
        rounded chip carrying a live dot and a name, the label was spending nine characters of a 360dp row
        saying what the row already looks like.

        On every screen except the one it names. The terminal draws these same sessions in its own bar, and
        two rows of the same pills — one of them 46 pixels of it — is the arrangement this surface exists to
        stop. Wrapped rather than given a second condition, because the strip's own visibility is about
        whether there are any tabs and this one is about which surface is up.
      -->
      <Panel Grid.Row="2" IsVisible="{Binding IsShowingPages}">
        <Border IsVisible="{Binding HasTabs}" Background="{StaticResource Sidebar}"
                BorderBrush="{StaticResource Border}" BorderThickness="0,1,0,0" Height="46">
          <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">
            <ItemsControl ItemsSource="{Binding Tabs}" Margin="12,0" VerticalAlignment="Center">
              <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate><StackPanel Orientation="Horizontal" Spacing="6" /></ItemsPanelTemplate>
              </ItemsControl.ItemsPanel>
              <ItemsControl.ItemTemplate>
                <DataTemplate x:DataType="vm:TerminalTabViewModel">
                  <Button Classes="row" MinHeight="34" Padding="13,0" CornerRadius="9"
                          Background="{StaticResource Panel}" BorderBrush="{StaticResource BorderMid}"
                          BorderThickness="1"
                          Command="{Binding $parent[views:PhoneShell].((vm:MainWindowViewModel)DataContext).SelectTabCommand}"
                          CommandParameter="{Binding}">
                    <StackPanel Orientation="Horizontal" Spacing="7" VerticalAlignment="Center">
                      <!--
                        Green only while there is a shell behind the tab. It used to be lit unconditionally,
                        which was true when a tab could not exist without a session; one can now —
                        connecting opens the tab first — and a dot that was green before anything had
                        answered would be the one thing on this strip claiming something untrue.
                      -->
                      <Ellipse Classes="dot" Classes.live="{Binding IsLive}" Width="6" Height="6"
                               VerticalAlignment="Center" />
                      <TextBlock Classes="mono" FontSize="11" Text="{Binding Label}" />
                    </StackPanel>
                  </Button>
                </DataTemplate>
              </ItemsControl.ItemTemplate>
            </ItemsControl>
          </ScrollViewer>
        </Border>
      </Panel>

      <!-- ============ navigation ============ -->
      <!--
        Gone while a terminal is showing, which is the whole of that surface's arrangement: the bar's four
        destinations are replaced by a back arrow and a + that leads to three of them, both in the terminal's
        own bar. See TerminalScreen.axaml.

        This one is bound directly rather than wrapped — its visibility is a single question and it has no
        second condition of its own to keep separate.
      -->
      <Border Grid.Row="3" IsVisible="{Binding IsShowingPages}"
              Background="{StaticResource Chrome}" BorderBrush="{StaticResource Border}"
              BorderThickness="0,1,0,0" Height="64">
        <Grid ColumnDefinitions="*,*,*,*">

          <views:NavButton Grid.Column="0" Label="Hosts" Glyph="▤" IsCurrent="{Binding IsHostsShowing}"
                           Command="{Binding ShowScreenCommand}"
                           CommandParameter="{x:Static vm:ShellScreen.Hosts}" />

          <!--
            The terminal is a surface rather than a page — see ShellSurface — so this one does not go
            through ShowScreen. Its own command is on the shell.

            The only entry here that never lights, and deliberately no longer tries: this bar is collapsed
            while the terminal is showing, so IsCurrent could only ever be read as false. Binding it anyway
            would be a rule about a state this control cannot be in. What marks the terminal as current is
            the surface filling the screen.
          -->
          <views:NavButton Grid.Column="1" Label="Terminal" Glyph="⌗"
                           Command="{Binding ShowTerminalCommand}" />

          <!--
            "Keychain", although the design's tab says Vault and the enum member is Vault. The split is a
            standing rule rather than an inconsistency: every sentence a user reads calls the encrypted
            store a keychain, and everything under the surface calls it a vault, because renaming the wire
            route, the tables and the CLR types would put an AAD resource type inside the blast radius of a
            find-and-replace. See docs/design-import-gaps.md. A tab reading Vault would be the one place the
            product surface leaked the implementation's word.
          -->
          <views:NavButton Grid.Column="2" Label="Keychain" Glyph="⚿" IsCurrent="{Binding IsVaultShowing}"
                           Command="{Binding ShowScreenCommand}"
                           CommandParameter="{x:Static vm:ShellScreen.Vault}" />

          <!--
            IsMoreSurface rather than IsMoreShowing: this tab stands for the hub and everything behind it,
            and a bar that went dark the moment you opened one of them would only ever light three of its
            four entries.
          -->
          <views:NavButton Grid.Column="3" Label="More" Glyph="≣" IsCurrent="{Binding IsMoreSurface}"
                           Command="{Binding ShowScreenCommand}"
                           CommandParameter="{x:Static vm:ShellScreen.More}" />

        </Grid>
      </Border>

    </Grid>

  </Panel>

</UserControl>
