<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.TeamsScreen"
             x:DataType="vm:TeamsViewModel"
             Background="{StaticResource Canvas}">

  <!--
    TEAMS, under MORE — and the one screen behind that hub the v2 phone design never drew.

    It is the reverse of every other entry in docs/design-import-gaps.md: a shipped screen the design had
    no slot for, rather than a drawn screen with nothing behind it. It is on the phone because an
    invitation is claimed by *signing in*, and the person being invited is at least as likely to be
    holding a phone as sitting at a desktop — a team the server has just put somebody into, visible only
    on a head they may never have installed, is a membership they cannot see.

    That argument is also why the invited list is drawn here and not treated as an administrator's detail:
    the people on it are the ones who cannot yet see the team, and the row says out loud that no mail was
    sent.

    So there is no mock-up to depart from. What this departs from instead is the desktop screen over the
    same view model, and every difference below is a phone difference rather than a second opinion.

    **The desktop's two columns are one.** A 268-pixel team list beside a members-and-vaults table does
    not exist at 360dp, so the three lists stack in one scrolling column with the teams at the top. That
    is the same thing HOSTS does with the desktop's sidebar and its connect column, and for the same
    reason.

    **Nothing scrolls inside anything.** The desktop caps its members and vaults lists at 240 and 200
    pixels so the two can sit above each other in one pane. Here every list is sized to its content and
    the screen's own ScrollViewer does all of the scrolling: a list that scrolls inside a page is a region
    a thumb has to find the edges of, and three of them on one screen is three ways to get stuck.

    ◆ **SHARE KEY is drawn and nothing that takes something away is.** That is a decision rather than a
    subset. Wrapping a vault key is the one act on this screen a server cannot perform at all — it needs a
    machine that already holds the key, and this phone is one — so a teams screen that could only be read
    would leave the product's central claim undemonstrated on the head most people carry. REMOVE MEMBER,
    WITHDRAW KEY and REVOKE INVITATION are the other half of that, and each of them acts on the first
    press: the view model's armed-confirmation state covers archiving a team and handing one over, and
    those three are not armed by it. The desktop guards them with a tooltip instead, which is a control a
    touch screen has no way to show. An irreversible revocation under a thumb with its explanation missing
    is the wrong trade, so all three stay on the desktop — where the sentence beside them is visible.
    Archiving and hand-over are not drawn either, for a plainer reason: they decide whether a team goes on
    existing and who controls it, which is not a thing to do while walking.

    **ADD MEMBER is not drawn either**, and it is the operation this screen least needs. It is an address
    typed into a box, a directory lookup, a role picker, and a paragraph beside it saying what adding
    somebody did *not* do — and since invitations arrived the ordinary way into a team is one the server
    claims at sign-in, which is what put this screen on the phone at all. Creating a team is here, because
    a team is where those invitations are sent from and it is two short fields.

    **The key-holder list under a vault is not drawn.** It is a fourth list, it belongs to the selected
    vault rather than to the team, and the view model publishes no flag saying whether it has anything in
    it — so a heading for it would sit over nothing whenever nobody holds a key, which is exactly the
    empty state this head insists comes from the view model rather than from markup. What the phone can
    answer about a vault is on the vault's own row: whether *this* machine can open it.

    **↻ and `+` both, because this screen has more reason to re-read than any other.** Nothing here is
    cached — it is all read from the server on arrival and again at the end of every command — so the one
    thing a member cannot otherwise see is a change somebody else just made: a vault key wrapped to them
    from a colleague's desktop, or a team they have this moment been invited into. On the desktop the
    re-read is leaving the rail and coming back, which is one click. Here it is a trip out to MORE and
    back, so the button earns its place. It binds to a real command rather than to ShowScreen(Team),
    which would set Screen to the value it already holds, raise nothing and reload nothing.
  -->

  <Grid RowDefinitions="Auto,Auto,Auto,*,Auto">

    <!-- ============ header ============ -->
    <Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto,Auto" Height="56" Margin="8,0">
      <Button Grid.Column="0" Classes="icon" Content="←"
              Command="{Binding $parent[views:PhoneShell].((vm:MainWindowViewModel)DataContext).ShowScreenCommand}"
              CommandParameter="{x:Static vm:ShellScreen.More}" />
      <TextBlock Grid.Column="1" Classes="heading" Text="Teams" Margin="4,0" />
      <Button Grid.Column="2" Classes="icon" Content="↻" Command="{Binding RefreshCommand}"
              IsEnabled="{Binding !IsBusy}" />
      <Button Grid.Column="3" Classes="icon accent" Content="+" Command="{Binding NewTeamCommand}"
              IsEnabled="{Binding !IsBusy}" />
    </Grid>

    <!-- ============ a new team ============ -->
    <!--
      Above the list rather than in place of it, which is the opposite of what the host and snippet
      editors do — and the difference is what the form is about. Those two edit a row that is on screen,
      so a card stacked over the list hides the thing being changed. This one is about a team that does
      not exist yet, and the teams that do are exactly the useful thing to be able to see while naming it:
      the slug has to be unique on this server, and the near misses are right underneath.
    -->
    <Border Grid.Row="1" Classes="card" Margin="12,0,12,8" IsVisible="{Binding IsCreatingTeam}">
      <StackPanel Spacing="10">
        <TextBlock Classes="label" Text="NEW TEAM" />

        <TextBox Classes="field" Text="{Binding NewTeamName}" PlaceholderText="name" />
        <TextBox Classes="field" Text="{Binding NewTeamSlug}" PlaceholderText="slug-for-urls" />

        <TextBlock Classes="body"
                   Text="The slug is lowercase letters, digits and hyphens, and has to be unique across this server. It is fixed once the team exists — a team can be renamed and its slug cannot." />

        <Grid ColumnDefinitions="*,8,*">
          <Button Grid.Column="0" Classes="primary" Height="44" Content="CREATE"
                  Command="{Binding CreateTeamCommand}" IsEnabled="{Binding !IsBusy}" />
          <Button Grid.Column="2" Classes="secondary" Height="44" Content="CANCEL"
                  Command="{Binding CancelNewTeamCommand}" />
        </Grid>
      </StackPanel>
    </Border>

    <!--
      Status, and it is the empty state as well: the view model writes "you are not in a team yet" into
      the same property it writes an offline notice and every command's outcome into. A literal here would
      be a second voice saying the same thing slightly differently.
    -->
    <TextBlock Grid.Row="2" Classes="detail" Margin="18,2,18,6" TextWrapping="Wrap"
               Text="{Binding Status}"
               IsVisible="{Binding Status, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />

    <!-- ============ the column ============ -->
    <ScrollViewer Grid.Row="3">
      <StackPanel Margin="0,0,0,18">

        <TextBlock Classes="section" Text="TEAMS" Margin="18,4,18,4" />

        <!--
          Rows as cards, filled when chosen, which is what HOSTS settled on in v2 and what the radius
          ladder calls a card: one item, one rule, one thing you act on. The fill is on the item rather
          than on a Border inside it so the rounding the theme draws for selection is the row's own.
        -->
        <ListBox ItemsSource="{Binding Teams}" SelectedItem="{Binding SelectedTeam}"
                 IsVisible="{Binding HasTeams}" Background="Transparent" BorderThickness="0">
          <ListBox.Styles>
            <Style Selector="ListBoxItem">
              <Setter Property="Padding" Value="0" />
              <Setter Property="MinHeight" Value="0" />
              <Setter Property="Margin" Value="10,1" />
              <Setter Property="CornerRadius" Value="12" />
            </Style>
            <Style Selector="ListBoxItem:selected /template/ ContentPresenter">
              <Setter Property="Background" Value="{StaticResource Active}" />
              <Setter Property="CornerRadius" Value="12" />
            </Style>
          </ListBox.Styles>
          <ListBox.ItemTemplate>
            <DataTemplate x:DataType="vm:TeamRowViewModel">
              <Grid ColumnDefinitions="*,Auto" MinHeight="54" Margin="14,11">
                <StackPanel Grid.Column="0" Spacing="3" VerticalAlignment="Center">
                  <TextBlock Classes="mono" FontSize="13.5" FontWeight="SemiBold" Text="{Binding Name}"
                             TextTrimming="CharacterEllipsis" />
                  <TextBlock Classes="detail" FontSize="10.5" Text="{Binding Detail}" />
                </StackPanel>

                <!-- The caller's own role in this team, which is what says why some of it is read-only. -->
                <Border Grid.Column="1" Classes="tag outline" Margin="8,0,0,0">
                  <TextBlock Text="{Binding Role}" />
                </Border>
              </Grid>
            </DataTemplate>
          </ListBox.ItemTemplate>
        </ListBox>

        <!-- ============ the chosen team ============ -->
        <StackPanel IsVisible="{Binding HasSelection}">

          <TextBlock Classes="section" Text="MEMBERS" Margin="18,18,18,4" />

          <ListBox ItemsSource="{Binding Members}" SelectedItem="{Binding SelectedMember}"
                   Background="Transparent" BorderThickness="0">
            <ListBox.Styles>
              <Style Selector="ListBoxItem">
                <Setter Property="Padding" Value="0" />
                <Setter Property="MinHeight" Value="0" />
                <Setter Property="Margin" Value="10,1" />
                <Setter Property="CornerRadius" Value="12" />
              </Style>
              <Style Selector="ListBoxItem:selected /template/ ContentPresenter">
                <Setter Property="Background" Value="{StaticResource Active}" />
                <Setter Property="CornerRadius" Value="12" />
              </Style>
            </ListBox.Styles>
            <ListBox.ItemTemplate>
              <DataTemplate x:DataType="vm:TeamMemberRowViewModel">
                <Grid ColumnDefinitions="*,Auto" MinHeight="54" Margin="14,11">
                  <StackPanel Grid.Column="0" Spacing="3" VerticalAlignment="Center">
                    <TextBlock Classes="mono" FontSize="13.5" FontWeight="SemiBold" Text="{Binding Name}"
                               TextTrimming="CharacterEllipsis" />
                    <TextBlock Classes="detail" FontSize="10.5" Text="{Binding Email}"
                               TextTrimming="CharacterEllipsis" />

                    <!--
                      ◆ The one fact on this row that decides whether the button at the foot of the screen
                      can do anything: an account with no published identity key has nothing for a vault
                      key to be wrapped to. One sentence, from the view model, painted twice rather than
                      written twice — the warning colour is the whole of the difference, and a converter
                      for it would hide that the two are the same string.

                      The published case is quiet rather than green. Green on this head means a shell is
                      open right now, and a published key is a durable fact about an account — borrowing
                      the status colour for it would be the second meaning that makes the first
                      unreadable. Only the missing key is coloured, because only it needs answering.
                    -->
                    <TextBlock Classes="detail" FontSize="10" TextWrapping="Wrap"
                               Foreground="{StaticResource TextDim}" Text="{Binding KeyState}"
                               IsVisible="{Binding Member.IsEnrolled}" />
                    <TextBlock Classes="detail" FontSize="10" TextWrapping="Wrap"
                               Foreground="{StaticResource WarnText}" Text="{Binding KeyState}"
                               IsVisible="{Binding !Member.IsEnrolled}" />

                    <!--
                      A date to the day, or that they have never been here at all. The view model writes
                      both, and neither is a guess: the server records the account's last authenticated
                      request at most once an hour, which is what makes a day the honest unit.
                    -->
                    <TextBlock Classes="detail" FontSize="9.5" Foreground="{StaticResource TextFaint}"
                               Text="{Binding LastActive}" />
                  </StackPanel>

                  <Border Grid.Column="1" Classes="tag outline" Margin="8,0,0,0">
                    <TextBlock Text="{Binding Role}" />
                  </Border>
                </Grid>
              </DataTemplate>
            </ListBox.ItemTemplate>
          </ListBox>

          <TextBlock Classes="body" Margin="18,10,18,0"
                     Text="Being in a team is what lets the server hand somebody this team's vaults. It is not what lets them read one: a vault key can only be wrapped by a machine that already holds it, which is what sharing below does." />

          <!-- ============ ◆ who has been asked and has not arrived ============ -->
          <!--
            The section this screen exists for, and the one the desktop had nothing to draw until
            invitations were built. Read-only here: withdrawing one is a control that acts on the first
            press, which is the line drawn at the top of this file.

            So these are cards rather than the flat rows above them, and the shape is the difference: a row
            that fills when you touch it is one of several you are choosing between, and there is nothing
            to choose here. An ItemsControl rather than a ListBox for the same reason — a list with a
            selection nothing reads would be a control offering something it cannot do.

            Gated on the view model's own count rather than left to stand over an empty list, because a
            team with nobody outstanding is the ordinary case and a permanent empty heading would make it
            look like a section that had failed to load.

            The waiting row carries the whole mechanism in its own sentence — no mail was sent, and they
            join when they first sign in here. That is the sentence somebody has to read, because every
            other product's version of this word means an email is on its way.
          -->
          <StackPanel IsVisible="{Binding HasInvitations}">
            <TextBlock Classes="section" Text="INVITED" Margin="18,18,18,4" />

            <ItemsControl ItemsSource="{Binding Invitations}">
              <ItemsControl.ItemTemplate>
                <DataTemplate x:DataType="vm:TeamInvitationRowViewModel">
                  <Border Classes="card" Margin="12,3">
                    <Grid ColumnDefinitions="*,Auto">
                      <StackPanel Grid.Column="0" Spacing="3" VerticalAlignment="Center">
                        <TextBlock Classes="mono" FontSize="12.5" Text="{Binding Email}"
                                   TextTrimming="CharacterEllipsis" />
                        <TextBlock Classes="detail" FontSize="10" TextWrapping="Wrap"
                                   Foreground="{StaticResource TextDim}" Text="{Binding State}"
                                   IsVisible="{Binding !IsPending}" />
                        <TextBlock Classes="detail" FontSize="10" TextWrapping="Wrap"
                                   Foreground="{StaticResource WarnText}" Text="{Binding State}"
                                   IsVisible="{Binding IsPending}" />
                      </StackPanel>
                      <Border Grid.Column="1" Classes="tag outline" Margin="8,0,0,0">
                        <TextBlock Text="{Binding Role}" />
                      </Border>
                    </Grid>
                  </Border>
                </DataTemplate>
              </ItemsControl.ItemTemplate>
            </ItemsControl>
          </StackPanel>

          <TextBlock Classes="section" Text="VAULTS" Margin="18,18,18,4" />

          <ListBox ItemsSource="{Binding Vaults}" SelectedItem="{Binding SelectedVault}"
                   Background="Transparent" BorderThickness="0">
            <ListBox.Styles>
              <Style Selector="ListBoxItem">
                <Setter Property="Padding" Value="0" />
                <Setter Property="MinHeight" Value="0" />
                <Setter Property="Margin" Value="10,1" />
                <Setter Property="CornerRadius" Value="12" />
              </Style>
              <Style Selector="ListBoxItem:selected /template/ ContentPresenter">
                <Setter Property="Background" Value="{StaticResource Active}" />
                <Setter Property="CornerRadius" Value="12" />
              </Style>
            </ListBox.Styles>
            <ListBox.ItemTemplate>
              <DataTemplate x:DataType="vm:TeamVaultRowViewModel">
                <StackPanel Spacing="3" MinHeight="54" Margin="14,11" VerticalAlignment="Center">
                  <TextBlock Classes="mono" FontSize="13.5" FontWeight="SemiBold" Text="{Binding Name}"
                             TextTrimming="CharacterEllipsis" />

                  <!--
                    Whether *this* phone can open it, which is a property of its keyring rather than
                    anything the server could answer. Painted the same two ways as the member's key
                    state above, because it is the same question asked from the other end.
                  -->
                  <TextBlock Classes="detail" FontSize="10.5" TextWrapping="Wrap"
                             Foreground="{StaticResource TextDim}" Text="{Binding State}"
                             IsVisible="{Binding IsReadable}" />
                  <TextBlock Classes="detail" FontSize="10.5" TextWrapping="Wrap"
                             Foreground="{StaticResource WarnText}" Text="{Binding State}"
                             IsVisible="{Binding !IsReadable}" />
                </StackPanel>
              </DataTemplate>
            </ListBox.ItemTemplate>
          </ListBox>

          <TextBlock Classes="body" Margin="18,10,18,0"
                     Text="A vault listed here that this phone has no key to stays listed and stays shut. That is the ordinary case rather than a fault: somebody has been added to the team and nobody has wrapped the key to them yet." />

        </StackPanel>

      </StackPanel>
    </ScrollViewer>

    <!-- ============ ◆ giving somebody the key ============ -->
    <!--
      Raised over the column when both halves of the act have been chosen, as HOSTS raises its connect bar
      and SNIPPETS its insert bar, and for the reason written there: there is no second column to put it
      in, so it names what it will do rather than relying on a selection being visible beside the button.

      Two wrappers rather than one condition. Sharing needs a member *and* a vault, and a binding cannot
      say `SelectedMember is not null && SelectedVault is not null` without a converter that does not
      exist — the log screen makes the same trade for the same reason. It also gets the halves in the
      right order: choosing who comes first, and until a vault is chosen there is nothing to offer them.
    -->
    <Panel Grid.Row="4" IsVisible="{Binding SelectedMember, Converter={x:Static ObjectConverters.IsNotNull}}">
      <Border IsVisible="{Binding SelectedVault, Converter={x:Static ObjectConverters.IsNotNull}}"
              Background="{StaticResource Chrome}" BorderBrush="{StaticResource Border}"
              BorderThickness="0,1,0,0" Padding="14,12">
        <StackPanel Spacing="9">

          <StackPanel Orientation="Horizontal" Spacing="8">
            <TextBlock Classes="label" Text="THE KEY TO" />
            <TextBlock Classes="mono" FontSize="11" Text="{Binding SelectedVault.Name}"
                       TextTrimming="CharacterEllipsis" VerticalAlignment="Center" />
          </StackPanel>

          <StackPanel Orientation="Horizontal" Spacing="8">
            <TextBlock Classes="label" Text="FOR" />
            <TextBlock Classes="mono" FontSize="11" Text="{Binding SelectedMember.Name}"
                       TextTrimming="CharacterEllipsis" VerticalAlignment="Center" />
          </StackPanel>

          <Button Classes="primary" Content="SHARE KEY" Command="{Binding ShareVaultCommand}"
                  IsEnabled="{Binding !IsBusy}" />

          <!--
            The sentence the desktop hangs off a tooltip, which a phone cannot show — so it is body text
            under the button, where it is read before the tap rather than after it. It is not decoration:
            the key-log check proves this server has been consistent with itself and nothing more.
          -->
          <TextBlock Classes="body"
                     Text="Their published key is checked against the server's append-only key log first, and nothing is wrapped if it does not appear there unchanged. That proves the server has been consistent with itself — not that the key is the right person's. Compare the fingerprint with them over a channel this server does not carry before sharing anything that matters." />

        </StackPanel>
      </Border>
    </Panel>

  </Grid>

</UserControl>
