feat(sprint-3): apply Survey Teal field UI

This commit is contained in:
Brent Perteet
2026-08-20 22:00:31 -05:00
parent f9fb9f59f4
commit 5e87d81bb6
16 changed files with 954 additions and 562 deletions

View File

@@ -5,80 +5,163 @@
xmlns:models="clr-namespace:FieldLogger.Models"
x:Class="FieldLogger.Views.HomePage"
x:DataType="vm:HomeViewModel"
Title="Field Logger">
Title="Field Logger"
BackgroundColor="{DynamicResource UlColorCanvas}">
<ScrollView>
<VerticalStackLayout Padding="16" Spacing="12">
<VerticalStackLayout Padding="16" Spacing="16">
<VerticalStackLayout Spacing="4">
<Label Text="FIELD LOGGER" FontSize="14" FontAttributes="Bold" CharacterSpacing="1.5"
TextColor="{DynamicResource UlColorPrimary}" />
<Label Text="Live field capture" Style="{StaticResource UlPageTitle}"
TextColor="{DynamicResource UlColorText}"
SemanticProperties.HeadingLevel="Level1" />
</VerticalStackLayout>
<!-- Device connection status -->
<Border StrokeThickness="0" Background="{AppThemeBinding Light=#F2F2F7, Dark=#1C1C1E}" StrokeShape="RoundRectangle 12" Padding="12">
<Grid ColumnDefinitions="16,*,Auto" RowDefinitions="Auto,Auto" RowSpacing="10" ColumnSpacing="10">
<Ellipse Grid.Row="0" Grid.Column="0" WidthRequest="12" HeightRequest="12" VerticalOptions="Center"
Fill="{Binding Manager.LocatorState, Converter={StaticResource StateColor}}" />
<VerticalStackLayout Grid.Row="0" Grid.Column="1" Spacing="0">
<Label Text="{Binding Manager.LocatorName, TargetNullValue='Locating Receiver — not selected'}" FontAttributes="Bold" />
<Label Text="{Binding Manager.LocatorState, Converter={StaticResource StateText}}" FontSize="12" TextColor="Gray" />
</VerticalStackLayout>
<Button Grid.Row="0" Grid.Column="2" Text="Select" FontSize="12" Padding="10,4"
Command="{Binding SelectLocatorCommand}" />
<Ellipse Grid.Row="1" Grid.Column="0" WidthRequest="12" HeightRequest="12" VerticalOptions="Center"
Fill="{Binding Manager.GpsState, Converter={StaticResource StateColor}}" />
<VerticalStackLayout Grid.Row="1" Grid.Column="1" Spacing="0">
<Label Text="{Binding Manager.GpsName, TargetNullValue='Maglink RTK GPS — not selected'}" FontAttributes="Bold" />
<Label Text="{Binding Manager.GpsState, Converter={StaticResource StateText}}" FontSize="12" TextColor="Gray" />
</VerticalStackLayout>
<Button Grid.Row="1" Grid.Column="2" Text="Select" FontSize="12" Padding="10,4"
Command="{Binding SelectGpsCommand}" />
<Border Style="{StaticResource UlCard}" BackgroundColor="{DynamicResource UlColorSurfaceRaised}"
Stroke="{DynamicResource UlColorBorder}" StrokeThickness="1"
StrokeShape="RoundRectangle 12" Padding="16"
SemanticProperties.Description="Active job and local capture count">
<Grid RowDefinitions="Auto,Auto,Auto" ColumnDefinitions="*,Auto" RowSpacing="8" ColumnSpacing="12">
<Label Text="ACTIVE JOB" FontSize="14" FontAttributes="Bold"
TextColor="{DynamicResource UlColorTextMuted}" />
<Label Grid.Row="1" Text="{Binding ActiveJobName}" FontSize="22" FontAttributes="Bold"
TextColor="{DynamicResource UlColorText}" LineBreakMode="TailTruncation" />
<Label Grid.Row="2" Text="{Binding ActiveJobPointSummary}" FontSize="16"
TextColor="{DynamicResource UlColorTextMuted}" />
<Button Grid.RowSpan="3" Grid.Column="1" Style="{StaticResource UlButtonSecondary}"
Text="Jobs" Command="{Binding SelectJobCommand}"
MinimumHeightRequest="{StaticResource UlTouchMinimum}" MinimumWidthRequest="72" FontAttributes="Bold"
SemanticProperties.Description="Choose or review the active job" />
</Grid>
</Border>
<!-- Live GNSS fix -->
<Border StrokeThickness="0" Background="{AppThemeBinding Light=#F2F2F7, Dark=#1C1C1E}" StrokeShape="RoundRectangle 12" Padding="12">
<VerticalStackLayout Spacing="4">
<HorizontalStackLayout Spacing="8">
<Label Text="GPS" FontAttributes="Bold" />
<Label Text="{Binding FixStatusLabel}" TextColor="DodgerBlue" FontAttributes="Bold" />
</HorizontalStackLayout>
<Label Text="{Binding FixSummary}" FontFamily="Courier New" FontSize="13" />
<Label Text="{Binding FixAccuracy}" FontSize="12" TextColor="Gray" />
</VerticalStackLayout>
<!-- Production capture remains receiver-triggered. This is deliberately guidance,
not an app button that would invent an unsupported device command. -->
<Border BackgroundColor="{DynamicResource UlColorPrimary}" StrokeThickness="0"
StrokeShape="RoundRectangle 20" Padding="20,16" MinimumHeightRequest="{StaticResource UlTouchPrimary}"
SemanticProperties.Description="Hardware capture action. Press the log button on the locating receiver.">
<Grid ColumnDefinitions="Auto,*" ColumnSpacing="12">
<Label Text="◎" FontSize="30" FontAttributes="Bold"
TextColor="{DynamicResource UlColorOnPrimary}" VerticalTextAlignment="Center" />
<VerticalStackLayout Grid.Column="1" Spacing="2" VerticalOptions="Center">
<Label Text="CAPTURE FROM RECEIVER" FontSize="18" FontAttributes="Bold"
TextColor="{DynamicResource UlColorOnPrimary}" />
<Label Text="{Binding CaptureReadinessText}" FontSize="14"
TextColor="{DynamicResource UlColorOnPrimary}" />
</VerticalStackLayout>
</Grid>
</Border>
<!-- Active job -->
<Border StrokeThickness="0" Background="{AppThemeBinding Light=#F2F2F7, Dark=#1C1C1E}" StrokeShape="RoundRectangle 12" Padding="12">
<Button Style="{StaticResource UlButtonPrimaryField}"
Text="Choose an active job" IsVisible="{Binding HasNoActiveJob}"
Command="{Binding SelectJobCommand}" MinimumHeightRequest="{StaticResource UlTouchComfortable}" FontAttributes="Bold"
SemanticProperties.Description="Capture is blocked. Choose or create an active job." />
<Label Text="DEVICE STATUS" FontSize="14" FontAttributes="Bold"
TextColor="{DynamicResource UlColorTextMuted}"
SemanticProperties.HeadingLevel="Level2" />
<Grid ColumnDefinitions="*,*" ColumnSpacing="8">
<Border Style="{StaticResource UlCard}" BackgroundColor="{DynamicResource UlColorSurfaceRaised}"
Stroke="{DynamicResource UlColorBorder}" StrokeShape="RoundRectangle 12"
Padding="12" MinimumHeightRequest="96">
<VerticalStackLayout Spacing="4">
<Label Text="LOCATOR" FontSize="14" FontAttributes="Bold"
TextColor="{DynamicResource UlColorTextMuted}" />
<Label Text="{Binding Manager.LocatorName, TargetNullValue='Not selected'}"
FontSize="16" FontAttributes="Bold" TextColor="{DynamicResource UlColorText}"
LineBreakMode="TailTruncation" />
<Label Text="{Binding Manager.LocatorState, Converter={StaticResource StateText}}"
FontSize="14" TextColor="{DynamicResource UlColorTextMuted}" />
<Button Style="{StaticResource UlButtonSecondary}"
Text="Select locator" Command="{Binding SelectLocatorCommand}"
MinimumHeightRequest="{StaticResource UlTouchMinimum}" Margin="0,4,0,0"
SemanticProperties.Description="Select the locating receiver" />
</VerticalStackLayout>
</Border>
<Border Grid.Column="1" Style="{StaticResource UlCard}" BackgroundColor="{DynamicResource UlColorSurfaceRaised}"
Stroke="{DynamicResource UlColorBorder}" StrokeShape="RoundRectangle 12"
Padding="12" MinimumHeightRequest="96">
<VerticalStackLayout Spacing="4">
<Label Text="RTK GPS" FontSize="14" FontAttributes="Bold"
TextColor="{DynamicResource UlColorTextMuted}" />
<Label Text="{Binding Manager.GpsName, TargetNullValue='Not selected'}"
FontSize="16" FontAttributes="Bold" TextColor="{DynamicResource UlColorText}"
LineBreakMode="TailTruncation" />
<Label Text="{Binding Manager.GpsState, Converter={StaticResource StateText}}"
FontSize="14" TextColor="{DynamicResource UlColorTextMuted}" />
<Button Style="{StaticResource UlButtonSecondary}"
Text="Select GPS" Command="{Binding SelectGpsCommand}"
MinimumHeightRequest="{StaticResource UlTouchMinimum}" Margin="0,4,0,0"
SemanticProperties.Description="Select the Maglink RTK GPS receiver" />
</VerticalStackLayout>
</Border>
</Grid>
<Border Style="{StaticResource UlCard}" BackgroundColor="{DynamicResource UlColorSurfaceRaised}"
Stroke="{DynamicResource UlColorBorder}" StrokeShape="RoundRectangle 12" Padding="16">
<VerticalStackLayout Spacing="8">
<Grid ColumnDefinitions="*,Auto">
<VerticalStackLayout Spacing="0">
<Label Text="{Binding ActiveJobName}" FontAttributes="Bold" FontSize="16" />
<Label FontSize="12" TextColor="Gray">
<Label.Text>
<Binding Path="PointCount" StringFormat="{}{0} points logged" />
</Label.Text>
</Label>
</VerticalStackLayout>
<HorizontalStackLayout Grid.Column="1" Spacing="6">
<Button Text="New Job" FontSize="12" Padding="10,4" Command="{Binding NewJobCommand}" />
<Button Text="Jobs" FontSize="12" Padding="10,4" Command="{Binding SelectJobCommand}" />
</HorizontalStackLayout>
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="12">
<Label Text="POSITION FIX" FontSize="14" FontAttributes="Bold"
TextColor="{DynamicResource UlColorTextMuted}" />
<Label Grid.Column="1" Text="{Binding FixStatusLabel}" FontSize="16" FontAttributes="Bold"
TextColor="{DynamicResource UlColorText}"
SemanticProperties.Description="Current GPS fix quality" />
</Grid>
<Label Text="Press the log button on the receiver to capture a point."
FontSize="12" TextColor="Gray" IsVisible="{Binding HasActiveJob}" />
<Label Text="{Binding SyncStatus}" FontSize="11" TextColor="DodgerBlue" />
<Label Text="{Binding FixSummary}" FontSize="18" FontFamily="{StaticResource UlTypeFamilyMono}"
TextColor="{DynamicResource UlColorText}" />
<Label Text="{Binding FixAccuracy}" FontSize="14"
TextColor="{DynamicResource UlColorTextMuted}" />
</VerticalStackLayout>
</Border>
<!-- Recent points -->
<Label Text="Recent Points" FontAttributes="Bold" Margin="4,8,0,0" />
<CollectionView ItemsSource="{Binding RecentPoints}" HeightRequest="320">
<Border Style="{StaticResource UlCard}" BackgroundColor="{DynamicResource UlColorSurfaceRaised}"
Stroke="{DynamicResource UlColorBorder}" StrokeShape="RoundRectangle 12" Padding="16">
<Grid ColumnDefinitions="Auto,*" ColumnSpacing="10">
<Label Text="↕" FontSize="22" TextColor="{DynamicResource UlColorPrimary}" />
<VerticalStackLayout Grid.Column="1" Spacing="2">
<Label Text="SYNC STATUS" FontSize="14" FontAttributes="Bold"
TextColor="{DynamicResource UlColorTextMuted}" />
<Label Text="{Binding SyncStatus}" FontSize="16" FontAttributes="Bold"
TextColor="{DynamicResource UlColorText}"
SemanticProperties.Description="Current synchronization status" />
</VerticalStackLayout>
</Grid>
</Border>
<Grid ColumnDefinitions="*,Auto">
<Label Text="RECENT CAPTURES" FontSize="14" FontAttributes="Bold"
TextColor="{DynamicResource UlColorTextMuted}"
SemanticProperties.HeadingLevel="Level2" />
<Button Grid.Column="1" Style="{StaticResource UlButtonSecondary}"
Text="View map" Command="{Binding ViewMapCommand}"
MinimumHeightRequest="{StaticResource UlTouchMinimum}" MinimumWidthRequest="96"
SemanticProperties.Description="View captured points on the map" />
</Grid>
<CollectionView ItemsSource="{Binding RecentPoints}" HeightRequest="360"
SemanticProperties.Description="Ten most recent locally saved capture points">
<CollectionView.EmptyView>
<Label Text="No points logged yet." TextColor="Gray" Margin="8" />
<Border Style="{StaticResource UlCard}" BackgroundColor="{DynamicResource UlColorSurfaceRaised}"
Stroke="{DynamicResource UlColorBorder}"
StrokeShape="RoundRectangle 12" Padding="20">
<VerticalStackLayout Spacing="6">
<Label Text="No captures yet" Style="{StaticResource UlEmptyStateTitle}"
HorizontalTextAlignment="Center" TextColor="{DynamicResource UlColorText}" />
<Label Text="With an active job, press LOG on the receiver to save the first point."
Style="{StaticResource UlEmptyStateBody}"
FontSize="14" HorizontalTextAlignment="Center"
TextColor="{DynamicResource UlColorTextMuted}" />
</VerticalStackLayout>
</Border>
</CollectionView.EmptyView>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:LoggedPoint">
<Border StrokeThickness="0" Background="{AppThemeBinding Light=#FAFAFA, Dark=#242426}"
StrokeShape="RoundRectangle 8" Padding="10" Margin="0,2">
<Grid ColumnDefinitions="*,Auto" RowDefinitions="Auto,Auto">
<Label Grid.Row="0" FontSize="13" FontAttributes="Bold">
<Border Style="{StaticResource UlJobRow}" BackgroundColor="{DynamicResource UlColorSurfaceRaised}"
Stroke="{DynamicResource UlColorBorder}"
StrokeShape="RoundRectangle 12" Padding="12" Margin="0,0,0,8"
MinimumHeightRequest="76">
<Grid ColumnDefinitions="*,Auto" RowDefinitions="Auto,Auto" RowSpacing="6" ColumnSpacing="12">
<Label FontSize="16" FontAttributes="Bold" TextColor="{DynamicResource UlColorText}">
<Label.Text>
<MultiBinding StringFormat="{}{0} · {1} Hz · depth {2}">
<Binding Path="Utility" Converter="{StaticResource UtilityName}" />
@@ -87,9 +170,10 @@
</MultiBinding>
</Label.Text>
</Label>
<Label Grid.Row="0" Grid.Column="1" FontSize="12" TextColor="Gray"
<Label Grid.Column="1" FontSize="14" TextColor="{DynamicResource UlColorTextMuted}"
Text="{Binding TimestampUtc, StringFormat='{0:HH:mm:ss}'}" />
<Label Grid.Row="1" Grid.ColumnSpan="2" FontSize="12" TextColor="Gray">
<Label Grid.Row="1" Grid.ColumnSpan="2" FontSize="14" FontFamily="{StaticResource UlTypeFamilyMono}"
TextColor="{DynamicResource UlColorTextMuted}">
<Label.Text>
<MultiBinding StringFormat="{}{0:F7}, {1:F7} · {2}">
<Binding Path="Latitude" />
@@ -103,7 +187,6 @@
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</VerticalStackLayout>
</ScrollView>
</ContentPage>