feat(sprint-3): apply Survey Teal field UI
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="Resources/Styles/GeneratedTokens.xaml" />
|
||||
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
|
||||
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
@@ -4,13 +4,20 @@
|
||||
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:views="clr-namespace:FieldLogger.Views"
|
||||
Title="Field Logger">
|
||||
Title="Field Logger"
|
||||
BackgroundColor="{DynamicResource UlColorCanvas}"
|
||||
ForegroundColor="{DynamicResource UlColorText}"
|
||||
TitleColor="{DynamicResource UlColorText}"
|
||||
UnselectedColor="{DynamicResource UlColorTextMuted}"
|
||||
TabBarBackgroundColor="{DynamicResource UlColorSurfaceRaised}"
|
||||
TabBarForegroundColor="{DynamicResource UlColorPrimary}"
|
||||
TabBarTitleColor="{DynamicResource UlColorPrimary}"
|
||||
TabBarUnselectedColor="{DynamicResource UlColorTextMuted}">
|
||||
|
||||
<TabBar>
|
||||
<ShellContent Title="Home" Route="home" ContentTemplate="{DataTemplate views:HomePage}" />
|
||||
<ShellContent Title="Jobs" Route="jobs" ContentTemplate="{DataTemplate views:JobsPage}" />
|
||||
<ShellContent Title="Map" Route="map" ContentTemplate="{DataTemplate views:MapPage}" />
|
||||
<ShellContent Title="Debug" Route="debug" ContentTemplate="{DataTemplate views:DebugPage}" />
|
||||
<ShellContent Title="Settings" Route="settings" ContentTemplate="{DataTemplate views:SettingsPage}" />
|
||||
</TabBar>
|
||||
|
||||
|
||||
@@ -10,5 +10,10 @@ public partial class AppShell : Shell
|
||||
|
||||
Routing.RegisterRoute("devicescan", typeof(DeviceScanPage));
|
||||
Routing.RegisterRoute("jobdetail", typeof(JobDetailPage));
|
||||
#if DEBUG
|
||||
// Keep diagnostics available to development builds without presenting Debug as
|
||||
// a production primary tab.
|
||||
Routing.RegisterRoute("debug", typeof(DebugPage));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,45 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<?xaml-comp compile="true" ?>
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
|
||||
|
||||
<!-- Note: For Android please see also Platforms\Android\Resources\values\colors.xml -->
|
||||
|
||||
<Color x:Key="Primary">#512BD4</Color>
|
||||
<Color x:Key="PrimaryDark">#ac99ea</Color>
|
||||
<Color x:Key="PrimaryDarkText">#242424</Color>
|
||||
<Color x:Key="Secondary">#DFD8F7</Color>
|
||||
<Color x:Key="SecondaryDarkText">#9880e5</Color>
|
||||
<Color x:Key="Tertiary">#2B0B98</Color>
|
||||
|
||||
<Color x:Key="White">White</Color>
|
||||
<Color x:Key="Black">Black</Color>
|
||||
<Color x:Key="Magenta">#D600AA</Color>
|
||||
<Color x:Key="MidnightBlue">#190649</Color>
|
||||
<Color x:Key="OffBlack">#1f1f1f</Color>
|
||||
|
||||
<Color x:Key="Gray100">#E1E1E1</Color>
|
||||
<Color x:Key="Gray200">#C8C8C8</Color>
|
||||
<Color x:Key="Gray300">#ACACAC</Color>
|
||||
<Color x:Key="Gray400">#919191</Color>
|
||||
<Color x:Key="Gray500">#6E6E6E</Color>
|
||||
<Color x:Key="Gray600">#404040</Color>
|
||||
<Color x:Key="Gray900">#212121</Color>
|
||||
<Color x:Key="Gray950">#141414</Color>
|
||||
|
||||
<SolidColorBrush x:Key="PrimaryBrush" Color="{StaticResource Primary}"/>
|
||||
<SolidColorBrush x:Key="SecondaryBrush" Color="{StaticResource Secondary}"/>
|
||||
<SolidColorBrush x:Key="TertiaryBrush" Color="{StaticResource Tertiary}"/>
|
||||
<SolidColorBrush x:Key="WhiteBrush" Color="{StaticResource White}"/>
|
||||
<SolidColorBrush x:Key="BlackBrush" Color="{StaticResource Black}"/>
|
||||
|
||||
<SolidColorBrush x:Key="Gray100Brush" Color="{StaticResource Gray100}"/>
|
||||
<SolidColorBrush x:Key="Gray200Brush" Color="{StaticResource Gray200}"/>
|
||||
<SolidColorBrush x:Key="Gray300Brush" Color="{StaticResource Gray300}"/>
|
||||
<SolidColorBrush x:Key="Gray400Brush" Color="{StaticResource Gray400}"/>
|
||||
<SolidColorBrush x:Key="Gray500Brush" Color="{StaticResource Gray500}"/>
|
||||
<SolidColorBrush x:Key="Gray600Brush" Color="{StaticResource Gray600}"/>
|
||||
<SolidColorBrush x:Key="Gray900Brush" Color="{StaticResource Gray900}"/>
|
||||
<SolidColorBrush x:Key="Gray950Brush" Color="{StaticResource Gray950}"/>
|
||||
<!--
|
||||
Color values and legacy aliases are generated into GeneratedTokens.xaml from
|
||||
meta/contracts/design-tokens.json. Keep palette literals out of this file.
|
||||
-->
|
||||
</ResourceDictionary>
|
||||
183
FieldLogger/Resources/Styles/GeneratedTokens.xaml
Normal file
183
FieldLogger/Resources/Styles/GeneratedTokens.xaml
Normal file
@@ -0,0 +1,183 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<?xaml-comp compile="true" ?>
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
|
||||
|
||||
<!-- GENERATED FILE — DO NOT EDIT.
|
||||
Source: meta/contracts/design-tokens.json v3.0.0
|
||||
Run: node meta/scripts/generate-design-tokens.mjs -->
|
||||
<x:String x:Key="UlTokenVersion">3.0.0</x:String>
|
||||
|
||||
<!-- Named mode values. Runtime theme switching replaces the unqualified semantic colors below. -->
|
||||
<Color x:Key="UlDefaultColorCanvas">#EEF3F2</Color>
|
||||
<Color x:Key="UlDefaultColorSurface">#FCFEFD</Color>
|
||||
<Color x:Key="UlDefaultColorSurfaceRaised">#FFFFFF</Color>
|
||||
<Color x:Key="UlDefaultColorSurfaceStrong">#14252A</Color>
|
||||
<Color x:Key="UlDefaultColorText">#14252A</Color>
|
||||
<Color x:Key="UlDefaultColorTextMuted">#5D6B6E</Color>
|
||||
<Color x:Key="UlDefaultColorPrimary">#0B7774</Color>
|
||||
<Color x:Key="UlDefaultColorPrimaryPressed">#075F5D</Color>
|
||||
<Color x:Key="UlDefaultColorAccent">#B82D46</Color>
|
||||
<Color x:Key="UlDefaultColorBorder">#C7D2D0</Color>
|
||||
<Color x:Key="UlDefaultColorFocus">#B82D46</Color>
|
||||
<Color x:Key="UlDefaultColorMap">#DCE9E7</Color>
|
||||
<Color x:Key="UlDefaultColorSuccess">#347A55</Color>
|
||||
<Color x:Key="UlDefaultColorWarning">#A85C00</Color>
|
||||
<Color x:Key="UlDefaultColorError">#B42318</Color>
|
||||
<Color x:Key="UlDefaultColorNeutral">#40565B</Color>
|
||||
<Color x:Key="UlDefaultColorDisabled">#819092</Color>
|
||||
<Color x:Key="UlDefaultColorOnStrong">#FFFFFF</Color>
|
||||
<Color x:Key="UlDefaultColorOnPrimary">#FFFFFF</Color>
|
||||
<Color x:Key="UlDefaultColorOnAccent">#FFFFFF</Color>
|
||||
|
||||
<Color x:Key="UlSunlightColorCanvas">#FFFFFF</Color>
|
||||
<Color x:Key="UlSunlightColorSurface">#FFFFFF</Color>
|
||||
<Color x:Key="UlSunlightColorSurfaceRaised">#FFFFFF</Color>
|
||||
<Color x:Key="UlSunlightColorSurfaceStrong">#000000</Color>
|
||||
<Color x:Key="UlSunlightColorText">#000000</Color>
|
||||
<Color x:Key="UlSunlightColorTextMuted">#344448</Color>
|
||||
<Color x:Key="UlSunlightColorPrimary">#075F5D</Color>
|
||||
<Color x:Key="UlSunlightColorPrimaryPressed">#14252A</Color>
|
||||
<Color x:Key="UlSunlightColorAccent">#982138</Color>
|
||||
<Color x:Key="UlSunlightColorBorder">#5D6B6E</Color>
|
||||
<Color x:Key="UlSunlightColorFocus">#982138</Color>
|
||||
<Color x:Key="UlSunlightColorMap">#E8F0EF</Color>
|
||||
<Color x:Key="UlSunlightColorSuccess">#245F40</Color>
|
||||
<Color x:Key="UlSunlightColorWarning">#754000</Color>
|
||||
<Color x:Key="UlSunlightColorError">#871A12</Color>
|
||||
<Color x:Key="UlSunlightColorNeutral">#14252A</Color>
|
||||
<Color x:Key="UlSunlightColorDisabled">#344448</Color>
|
||||
<Color x:Key="UlSunlightColorOnStrong">#FFFFFF</Color>
|
||||
<Color x:Key="UlSunlightColorOnPrimary">#FFFFFF</Color>
|
||||
<Color x:Key="UlSunlightColorOnAccent">#FFFFFF</Color>
|
||||
|
||||
<!-- Active values start in default mode. All handwritten styles consume only these keys. -->
|
||||
<Color x:Key="UlColorCanvas">#EEF3F2</Color>
|
||||
<SolidColorBrush x:Key="UlBrushCanvas" Color="{StaticResource UlColorCanvas}" />
|
||||
<Color x:Key="UlColorSurface">#FCFEFD</Color>
|
||||
<SolidColorBrush x:Key="UlBrushSurface" Color="{StaticResource UlColorSurface}" />
|
||||
<Color x:Key="UlColorSurfaceRaised">#FFFFFF</Color>
|
||||
<SolidColorBrush x:Key="UlBrushSurfaceRaised" Color="{StaticResource UlColorSurfaceRaised}" />
|
||||
<Color x:Key="UlColorSurfaceStrong">#14252A</Color>
|
||||
<SolidColorBrush x:Key="UlBrushSurfaceStrong" Color="{StaticResource UlColorSurfaceStrong}" />
|
||||
<Color x:Key="UlColorText">#14252A</Color>
|
||||
<SolidColorBrush x:Key="UlBrushText" Color="{StaticResource UlColorText}" />
|
||||
<Color x:Key="UlColorTextMuted">#5D6B6E</Color>
|
||||
<SolidColorBrush x:Key="UlBrushTextMuted" Color="{StaticResource UlColorTextMuted}" />
|
||||
<Color x:Key="UlColorPrimary">#0B7774</Color>
|
||||
<SolidColorBrush x:Key="UlBrushPrimary" Color="{StaticResource UlColorPrimary}" />
|
||||
<Color x:Key="UlColorPrimaryPressed">#075F5D</Color>
|
||||
<SolidColorBrush x:Key="UlBrushPrimaryPressed" Color="{StaticResource UlColorPrimaryPressed}" />
|
||||
<Color x:Key="UlColorAccent">#B82D46</Color>
|
||||
<SolidColorBrush x:Key="UlBrushAccent" Color="{StaticResource UlColorAccent}" />
|
||||
<Color x:Key="UlColorBorder">#C7D2D0</Color>
|
||||
<SolidColorBrush x:Key="UlBrushBorder" Color="{StaticResource UlColorBorder}" />
|
||||
<Color x:Key="UlColorFocus">#B82D46</Color>
|
||||
<SolidColorBrush x:Key="UlBrushFocus" Color="{StaticResource UlColorFocus}" />
|
||||
<Color x:Key="UlColorMap">#DCE9E7</Color>
|
||||
<SolidColorBrush x:Key="UlBrushMap" Color="{StaticResource UlColorMap}" />
|
||||
<Color x:Key="UlColorSuccess">#347A55</Color>
|
||||
<SolidColorBrush x:Key="UlBrushSuccess" Color="{StaticResource UlColorSuccess}" />
|
||||
<Color x:Key="UlColorWarning">#A85C00</Color>
|
||||
<SolidColorBrush x:Key="UlBrushWarning" Color="{StaticResource UlColorWarning}" />
|
||||
<Color x:Key="UlColorError">#B42318</Color>
|
||||
<SolidColorBrush x:Key="UlBrushError" Color="{StaticResource UlColorError}" />
|
||||
<Color x:Key="UlColorNeutral">#40565B</Color>
|
||||
<SolidColorBrush x:Key="UlBrushNeutral" Color="{StaticResource UlColorNeutral}" />
|
||||
<Color x:Key="UlColorDisabled">#819092</Color>
|
||||
<SolidColorBrush x:Key="UlBrushDisabled" Color="{StaticResource UlColorDisabled}" />
|
||||
<Color x:Key="UlColorOnStrong">#FFFFFF</Color>
|
||||
<SolidColorBrush x:Key="UlBrushOnStrong" Color="{StaticResource UlColorOnStrong}" />
|
||||
<Color x:Key="UlColorOnPrimary">#FFFFFF</Color>
|
||||
<SolidColorBrush x:Key="UlBrushOnPrimary" Color="{StaticResource UlColorOnPrimary}" />
|
||||
<Color x:Key="UlColorOnAccent">#FFFFFF</Color>
|
||||
<SolidColorBrush x:Key="UlBrushOnAccent" Color="{StaticResource UlColorOnAccent}" />
|
||||
|
||||
<!-- Temporary aliases keep unmigrated MAUI screens compatible without a second color source. -->
|
||||
<Color x:Key="Primary">#0B7774</Color>
|
||||
<SolidColorBrush x:Key="PrimaryBrush" Color="{StaticResource Primary}" />
|
||||
<Color x:Key="PrimaryDark">#075F5D</Color>
|
||||
<SolidColorBrush x:Key="PrimaryDarkBrush" Color="{StaticResource PrimaryDark}" />
|
||||
<Color x:Key="PrimaryDarkText">#14252A</Color>
|
||||
<SolidColorBrush x:Key="PrimaryDarkTextBrush" Color="{StaticResource PrimaryDarkText}" />
|
||||
<Color x:Key="Secondary">#DCE9E7</Color>
|
||||
<SolidColorBrush x:Key="SecondaryBrush" Color="{StaticResource Secondary}" />
|
||||
<Color x:Key="SecondaryDarkText">#5D6B6E</Color>
|
||||
<SolidColorBrush x:Key="SecondaryDarkTextBrush" Color="{StaticResource SecondaryDarkText}" />
|
||||
<Color x:Key="Tertiary">#B82D46</Color>
|
||||
<SolidColorBrush x:Key="TertiaryBrush" Color="{StaticResource Tertiary}" />
|
||||
<Color x:Key="White">#FFFFFF</Color>
|
||||
<SolidColorBrush x:Key="WhiteBrush" Color="{StaticResource White}" />
|
||||
<Color x:Key="Black">#14252A</Color>
|
||||
<SolidColorBrush x:Key="BlackBrush" Color="{StaticResource Black}" />
|
||||
<Color x:Key="Magenta">#B82D46</Color>
|
||||
<SolidColorBrush x:Key="MagentaBrush" Color="{StaticResource Magenta}" />
|
||||
<Color x:Key="MidnightBlue">#14252A</Color>
|
||||
<SolidColorBrush x:Key="MidnightBlueBrush" Color="{StaticResource MidnightBlue}" />
|
||||
<Color x:Key="OffBlack">#14252A</Color>
|
||||
<SolidColorBrush x:Key="OffBlackBrush" Color="{StaticResource OffBlack}" />
|
||||
<Color x:Key="Gray100">#EEF3F2</Color>
|
||||
<SolidColorBrush x:Key="Gray100Brush" Color="{StaticResource Gray100}" />
|
||||
<Color x:Key="Gray200">#C7D2D0</Color>
|
||||
<SolidColorBrush x:Key="Gray200Brush" Color="{StaticResource Gray200}" />
|
||||
<Color x:Key="Gray300">#819092</Color>
|
||||
<SolidColorBrush x:Key="Gray300Brush" Color="{StaticResource Gray300}" />
|
||||
<Color x:Key="Gray400">#5D6B6E</Color>
|
||||
<SolidColorBrush x:Key="Gray400Brush" Color="{StaticResource Gray400}" />
|
||||
<Color x:Key="Gray500">#5D6B6E</Color>
|
||||
<SolidColorBrush x:Key="Gray500Brush" Color="{StaticResource Gray500}" />
|
||||
<Color x:Key="Gray600">#40565B</Color>
|
||||
<SolidColorBrush x:Key="Gray600Brush" Color="{StaticResource Gray600}" />
|
||||
<Color x:Key="Gray900">#14252A</Color>
|
||||
<SolidColorBrush x:Key="Gray900Brush" Color="{StaticResource Gray900}" />
|
||||
<Color x:Key="Gray950">#14252A</Color>
|
||||
<SolidColorBrush x:Key="Gray950Brush" Color="{StaticResource Gray950}" />
|
||||
|
||||
<!-- Cross-platform dimensions are dp in MAUI and generated as px on the web. -->
|
||||
<x:Double x:Key="UlSpace2xs">4</x:Double>
|
||||
<x:Double x:Key="UlSpaceXs">8</x:Double>
|
||||
<x:Double x:Key="UlSpaceSm">12</x:Double>
|
||||
<x:Double x:Key="UlSpaceMd">16</x:Double>
|
||||
<x:Double x:Key="UlSpaceLg">24</x:Double>
|
||||
<x:Double x:Key="UlSpaceXl">32</x:Double>
|
||||
<x:Double x:Key="UlSpace2xl">48</x:Double>
|
||||
<x:Double x:Key="UlRadiusSm">8</x:Double>
|
||||
<x:Double x:Key="UlRadiusMd">12</x:Double>
|
||||
<x:Double x:Key="UlRadiusLg">20</x:Double>
|
||||
<x:Double x:Key="UlRadiusPill">999</x:Double>
|
||||
<x:Double x:Key="UlTouchMinimum">48</x:Double>
|
||||
<x:Double x:Key="UlTouchComfortable">56</x:Double>
|
||||
<x:Double x:Key="UlTouchPrimary">64</x:Double>
|
||||
|
||||
<!-- IBM Plex is the target family. Checked-in Open Sans/system mono are offline-safe fallbacks until licensed Plex assets land. -->
|
||||
<x:String x:Key="UlTypeFamilySans">OpenSansRegular</x:String>
|
||||
<x:String x:Key="UlTypeFamilySansStrong">OpenSansSemibold</x:String>
|
||||
<x:String x:Key="UlTypeFamilyMono">monospace</x:String>
|
||||
<x:Double x:Key="UlTypeDisplaySize">40</x:Double>
|
||||
<x:Double x:Key="UlTypeDisplayLineHeight">48</x:Double>
|
||||
<x:Int32 x:Key="UlTypeDisplayWeight">700</x:Int32>
|
||||
<x:Double x:Key="UlTypePageSize">28</x:Double>
|
||||
<x:Double x:Key="UlTypePageLineHeight">34</x:Double>
|
||||
<x:Int32 x:Key="UlTypePageWeight">700</x:Int32>
|
||||
<x:Double x:Key="UlTypeSectionSize">22</x:Double>
|
||||
<x:Double x:Key="UlTypeSectionLineHeight">28</x:Double>
|
||||
<x:Int32 x:Key="UlTypeSectionWeight">600</x:Int32>
|
||||
<x:Double x:Key="UlTypeBodySize">16</x:Double>
|
||||
<x:Double x:Key="UlTypeBodyLineHeight">24</x:Double>
|
||||
<x:Int32 x:Key="UlTypeBodyWeight">400</x:Int32>
|
||||
<x:Double x:Key="UlTypeBodySmSize">14</x:Double>
|
||||
<x:Double x:Key="UlTypeBodySmLineHeight">20</x:Double>
|
||||
<x:Int32 x:Key="UlTypeBodySmWeight">400</x:Int32>
|
||||
<x:Double x:Key="UlTypeLabelSize">14</x:Double>
|
||||
<x:Double x:Key="UlTypeLabelLineHeight">20</x:Double>
|
||||
<x:Int32 x:Key="UlTypeLabelWeight">600</x:Int32>
|
||||
<x:Double x:Key="UlTypeMonoSize">16</x:Double>
|
||||
<x:Double x:Key="UlTypeMonoLineHeight">22</x:Double>
|
||||
<x:Int32 x:Key="UlTypeMonoWeight">500</x:Int32>
|
||||
<x:UInt32 x:Key="UlMotionFast">120</x:UInt32>
|
||||
<x:UInt32 x:Key="UlMotionBase">200</x:UInt32>
|
||||
<x:Double x:Key="UlBreakpointCompact">600</x:Double>
|
||||
<x:Double x:Key="UlBreakpointMedium">900</x:Double>
|
||||
<x:Double x:Key="UlBreakpointWide">1200</x:Double>
|
||||
</ResourceDictionary>
|
||||
@@ -1,444 +1,293 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<?xaml-comp compile="true" ?>
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
|
||||
|
||||
<!-- Survey Teal shared component foundation. DynamicResource colors allow sunlight switching. -->
|
||||
<Style TargetType="Page" ApplyToDerivedTypes="True">
|
||||
<Setter Property="BackgroundColor" Value="{DynamicResource UlColorCanvas}" />
|
||||
</Style>
|
||||
<Style TargetType="ActivityIndicator">
|
||||
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
|
||||
<Setter Property="Color" Value="{DynamicResource UlColorPrimary}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="IndicatorView">
|
||||
<Setter Property="IndicatorColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}"/>
|
||||
<Setter Property="SelectedIndicatorColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray100}}"/>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="Stroke" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
|
||||
<Setter Property="StrokeShape" Value="Rectangle"/>
|
||||
<Setter Property="BackgroundColor" Value="{DynamicResource UlColorSurface}" />
|
||||
<Setter Property="Stroke" Value="{DynamicResource UlColorBorder}" />
|
||||
<Setter Property="StrokeThickness" Value="1" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="BoxView">
|
||||
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" />
|
||||
<Setter Property="StrokeShape" Value="RoundRectangle 12" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource PrimaryDarkText}}" />
|
||||
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource PrimaryDark}}" />
|
||||
<Setter Property="FontFamily" Value="OpenSansRegular"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="TextColor" Value="{DynamicResource UlColorOnPrimary}" />
|
||||
<Setter Property="BackgroundColor" Value="{DynamicResource UlColorPrimary}" />
|
||||
<Setter Property="FontFamily" Value="{StaticResource UlTypeFamilySansStrong}" />
|
||||
<Setter Property="FontSize" Value="{StaticResource UlTypeLabelSize}" />
|
||||
<Setter Property="FontAttributes" Value="Bold" />
|
||||
<Setter Property="BorderColor" Value="Transparent" />
|
||||
<Setter Property="BorderWidth" Value="0" />
|
||||
<Setter Property="CornerRadius" Value="8"/>
|
||||
<Setter Property="Padding" Value="14,10"/>
|
||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
||||
<Setter Property="CornerRadius" Value="12" />
|
||||
<Setter Property="Padding" Value="16,12" />
|
||||
<Setter Property="MinimumHeightRequest" Value="{StaticResource UlTouchMinimum}" />
|
||||
<Setter Property="MinimumWidthRequest" Value="{StaticResource UlTouchMinimum}" />
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState x:Name="Pressed">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" />
|
||||
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray600}}" />
|
||||
<Setter Property="BackgroundColor" Value="{DynamicResource UlColorPrimaryPressed}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="PointerOver" />
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="CheckBox">
|
||||
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
|
||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
<Setter Property="TextColor" Value="{DynamicResource UlColorSurfaceStrong}" />
|
||||
<Setter Property="BackgroundColor" Value="{DynamicResource UlColorDisabled}" />
|
||||
<Setter Property="Opacity" Value="0.7" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="FocusStates">
|
||||
<VisualState x:Name="Unfocused" />
|
||||
<VisualState x:Name="Focused">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="BorderColor" Value="{DynamicResource UlColorFocus}" />
|
||||
<Setter Property="BorderWidth" Value="3" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="DatePicker">
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
|
||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
||||
<Setter Property="FontFamily" Value="OpenSansRegular"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
<Style x:Key="UlButtonPrimary" TargetType="Button" />
|
||||
<Style x:Key="UlButtonSecondary" TargetType="Button">
|
||||
<Setter Property="TextColor" Value="{DynamicResource UlColorPrimary}" />
|
||||
<Setter Property="BackgroundColor" Value="{DynamicResource UlColorSurface}" />
|
||||
<Setter Property="BorderColor" Value="{DynamicResource UlColorPrimary}" />
|
||||
<Setter Property="BorderWidth" Value="2" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Editor">
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
|
||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
||||
<Setter Property="FontFamily" Value="OpenSansRegular"/>
|
||||
<Setter Property="FontSize" Value="14" />
|
||||
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
|
||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
<Style x:Key="UlButtonAccent" TargetType="Button">
|
||||
<Setter Property="TextColor" Value="{DynamicResource UlColorOnAccent}" />
|
||||
<Setter Property="BackgroundColor" Value="{DynamicResource UlColorAccent}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Entry">
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
|
||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
||||
<Setter Property="FontFamily" Value="OpenSansRegular"/>
|
||||
<Setter Property="FontSize" Value="14" />
|
||||
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
|
||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
<Style x:Key="UlButtonPrimaryField" TargetType="Button">
|
||||
<Setter Property="MinimumHeightRequest" Value="{StaticResource UlTouchPrimary}" />
|
||||
<Setter Property="FontSize" Value="{StaticResource UlTypeBodySize}" />
|
||||
<Setter Property="CornerRadius" Value="20" />
|
||||
<Setter Property="Padding" Value="24,16" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="ImageButton">
|
||||
<Setter Property="Opacity" Value="1" />
|
||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
||||
<Setter Property="BorderColor" Value="Transparent" />
|
||||
<Setter Property="BorderWidth" Value="0" />
|
||||
<Setter Property="CornerRadius" Value="0"/>
|
||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
||||
<Setter Property="CornerRadius" Value="12" />
|
||||
<Setter Property="MinimumHeightRequest" Value="{StaticResource UlTouchMinimum}" />
|
||||
<Setter Property="MinimumWidthRequest" Value="{StaticResource UlTouchMinimum}" />
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="Opacity" Value="0.5" />
|
||||
</VisualState.Setters>
|
||||
<VisualState x:Name="Pressed">
|
||||
<VisualState.Setters><Setter Property="Opacity" Value="0.72" /></VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters><Setter Property="Opacity" Value="0.45" /></VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="PointerOver" />
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
</Style>
|
||||
<Style x:Key="UlIconButton" TargetType="ImageButton">
|
||||
<Setter Property="BackgroundColor" Value="{DynamicResource UlColorSurface}" />
|
||||
<Setter Property="BorderColor" Value="{DynamicResource UlColorBorder}" />
|
||||
<Setter Property="BorderWidth" Value="1" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Label">
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
|
||||
<Setter Property="TextColor" Value="{DynamicResource UlColorText}" />
|
||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
||||
<Setter Property="FontFamily" Value="OpenSansRegular" />
|
||||
<Setter Property="FontSize" Value="14" />
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
<Setter Property="FontFamily" Value="{StaticResource UlTypeFamilySans}" />
|
||||
<Setter Property="FontSize" Value="{StaticResource UlTypeBodySize}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Span">
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
|
||||
<Setter Property="TextColor" Value="{DynamicResource UlColorText}" />
|
||||
<Setter Property="FontFamily" Value="{StaticResource UlTypeFamilySans}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Label" x:Key="Headline">
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource MidnightBlue}, Dark={StaticResource White}}" />
|
||||
<Setter Property="FontSize" Value="32" />
|
||||
<Style x:Key="UlPageTitle" TargetType="Label">
|
||||
<Setter Property="FontFamily" Value="{StaticResource UlTypeFamilySansStrong}" />
|
||||
<Setter Property="FontAttributes" Value="Bold" />
|
||||
<Setter Property="FontSize" Value="{StaticResource UlTypePageSize}" />
|
||||
</Style>
|
||||
<Style x:Key="UlSectionTitle" TargetType="Label">
|
||||
<Setter Property="FontFamily" Value="{StaticResource UlTypeFamilySansStrong}" />
|
||||
<Setter Property="FontAttributes" Value="Bold" />
|
||||
<Setter Property="FontSize" Value="{StaticResource UlTypeSectionSize}" />
|
||||
</Style>
|
||||
<Style x:Key="UlBodyMuted" TargetType="Label">
|
||||
<Setter Property="TextColor" Value="{DynamicResource UlColorTextMuted}" />
|
||||
</Style>
|
||||
<Style x:Key="UlTechnicalValue" TargetType="Label">
|
||||
<Setter Property="FontFamily" Value="{StaticResource UlTypeFamilyMono}" />
|
||||
<Setter Property="FontSize" Value="{StaticResource UlTypeMonoSize}" />
|
||||
</Style>
|
||||
<Style x:Key="Headline" TargetType="Label" BasedOn="{StaticResource UlPageTitle}">
|
||||
<Setter Property="HorizontalOptions" Value="Center" />
|
||||
<Setter Property="HorizontalTextAlignment" Value="Center" />
|
||||
</Style>
|
||||
<Style x:Key="SubHeadline" TargetType="Label" BasedOn="{StaticResource UlSectionTitle}">
|
||||
<Setter Property="HorizontalOptions" Value="Center" />
|
||||
<Setter Property="HorizontalTextAlignment" Value="Center" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Label" x:Key="SubHeadline">
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource MidnightBlue}, Dark={StaticResource White}}" />
|
||||
<Setter Property="FontSize" Value="24" />
|
||||
<Setter Property="HorizontalOptions" Value="Center" />
|
||||
<Style x:Key="UlCard" TargetType="Border">
|
||||
<Setter Property="BackgroundColor" Value="{DynamicResource UlColorSurfaceRaised}" />
|
||||
<Setter Property="Stroke" Value="{DynamicResource UlColorBorder}" />
|
||||
<Setter Property="StrokeThickness" Value="1" />
|
||||
<Setter Property="StrokeShape" Value="RoundRectangle 12" />
|
||||
<Setter Property="Padding" Value="16" />
|
||||
<Setter Property="Margin" Value="0,0,0,12" />
|
||||
</Style>
|
||||
<Style x:Key="UlJobRow" TargetType="Border">
|
||||
<Setter Property="BackgroundColor" Value="{DynamicResource UlColorSurface}" />
|
||||
<Setter Property="Stroke" Value="{DynamicResource UlColorBorder}" />
|
||||
<Setter Property="StrokeThickness" Value="1" />
|
||||
<Setter Property="Padding" Value="16,12" />
|
||||
<Setter Property="MinimumHeightRequest" Value="{StaticResource UlTouchComfortable}" />
|
||||
</Style>
|
||||
<Style x:Key="UlStatusBadge" TargetType="Border">
|
||||
<Setter Property="BackgroundColor" Value="{DynamicResource UlColorSurface}" />
|
||||
<Setter Property="Stroke" Value="{DynamicResource UlColorNeutral}" />
|
||||
<Setter Property="StrokeThickness" Value="1" />
|
||||
<Setter Property="StrokeShape" Value="RoundRectangle 999" />
|
||||
<Setter Property="Padding" Value="8,4" />
|
||||
<!-- Consumers must supply visible status text and an icon; color is supplemental. -->
|
||||
</Style>
|
||||
<Style x:Key="UlDeviceChip" TargetType="Border" BasedOn="{StaticResource UlStatusBadge}">
|
||||
<Setter Property="MinimumHeightRequest" Value="{StaticResource UlTouchMinimum}" />
|
||||
<Setter Property="Padding" Value="12,8" />
|
||||
</Style>
|
||||
<Style x:Key="UlMetricValue" TargetType="Label">
|
||||
<Setter Property="FontFamily" Value="{StaticResource UlTypeFamilyMono}" />
|
||||
<Setter Property="FontAttributes" Value="Bold" />
|
||||
<Setter Property="FontSize" Value="{StaticResource UlTypeDisplaySize}" />
|
||||
</Style>
|
||||
<Style x:Key="UlEmptyStateTitle" TargetType="Label" BasedOn="{StaticResource UlSectionTitle}">
|
||||
<Setter Property="HorizontalTextAlignment" Value="Center" />
|
||||
</Style>
|
||||
<Style x:Key="UlEmptyStateBody" TargetType="Label" BasedOn="{StaticResource UlBodyMuted}">
|
||||
<Setter Property="HorizontalTextAlignment" Value="Center" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="ListView">
|
||||
<Setter Property="SeparatorColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
|
||||
<Setter Property="RefreshControlColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
|
||||
<Style TargetType="Entry">
|
||||
<Setter Property="TextColor" Value="{DynamicResource UlColorText}" />
|
||||
<Setter Property="PlaceholderColor" Value="{DynamicResource UlColorTextMuted}" />
|
||||
<Setter Property="BackgroundColor" Value="{DynamicResource UlColorSurface}" />
|
||||
<Setter Property="FontFamily" Value="{StaticResource UlTypeFamilySans}" />
|
||||
<Setter Property="FontSize" Value="{StaticResource UlTypeBodySize}" />
|
||||
<Setter Property="MinimumHeightRequest" Value="{StaticResource UlTouchMinimum}" />
|
||||
<Setter Property="MinimumWidthRequest" Value="{StaticResource UlTouchMinimum}" />
|
||||
</Style>
|
||||
<Style x:Key="UlInput" TargetType="Entry" />
|
||||
<Style TargetType="Editor">
|
||||
<Setter Property="TextColor" Value="{DynamicResource UlColorText}" />
|
||||
<Setter Property="PlaceholderColor" Value="{DynamicResource UlColorTextMuted}" />
|
||||
<Setter Property="BackgroundColor" Value="{DynamicResource UlColorSurface}" />
|
||||
<Setter Property="FontFamily" Value="{StaticResource UlTypeFamilySans}" />
|
||||
<Setter Property="FontSize" Value="{StaticResource UlTypeBodySize}" />
|
||||
<Setter Property="MinimumHeightRequest" Value="{StaticResource UlTouchComfortable}" />
|
||||
<Setter Property="MinimumWidthRequest" Value="{StaticResource UlTouchMinimum}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Picker">
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
|
||||
<Setter Property="TitleColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
|
||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
||||
<Setter Property="FontFamily" Value="OpenSansRegular"/>
|
||||
<Setter Property="FontSize" Value="14" />
|
||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
<Setter Property="TitleColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
<Setter Property="TextColor" Value="{DynamicResource UlColorText}" />
|
||||
<Setter Property="TitleColor" Value="{DynamicResource UlColorTextMuted}" />
|
||||
<Setter Property="BackgroundColor" Value="{DynamicResource UlColorSurface}" />
|
||||
<Setter Property="FontFamily" Value="{StaticResource UlTypeFamilySans}" />
|
||||
<Setter Property="FontSize" Value="{StaticResource UlTypeBodySize}" />
|
||||
<Setter Property="MinimumHeightRequest" Value="{StaticResource UlTouchMinimum}" />
|
||||
<Setter Property="MinimumWidthRequest" Value="{StaticResource UlTouchMinimum}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="ProgressBar">
|
||||
<Setter Property="ProgressColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="ProgressColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
<Style TargetType="DatePicker">
|
||||
<Setter Property="TextColor" Value="{DynamicResource UlColorText}" />
|
||||
<Setter Property="BackgroundColor" Value="{DynamicResource UlColorSurface}" />
|
||||
<Setter Property="FontFamily" Value="{StaticResource UlTypeFamilySans}" />
|
||||
<Setter Property="FontSize" Value="{StaticResource UlTypeBodySize}" />
|
||||
<Setter Property="MinimumHeightRequest" Value="{StaticResource UlTouchMinimum}" />
|
||||
<Setter Property="MinimumWidthRequest" Value="{StaticResource UlTouchMinimum}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="RadioButton">
|
||||
<Setter Property="BackgroundColor" Value="Transparent"/>
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
|
||||
<Setter Property="FontFamily" Value="OpenSansRegular"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="RefreshView">
|
||||
<Setter Property="RefreshColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="SearchBar">
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
|
||||
<Setter Property="PlaceholderColor" Value="{StaticResource Gray500}" />
|
||||
<Setter Property="CancelButtonColor" Value="{StaticResource Gray500}" />
|
||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
||||
<Setter Property="FontFamily" Value="OpenSansRegular" />
|
||||
<Setter Property="FontSize" Value="14" />
|
||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="SearchHandler">
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
|
||||
<Setter Property="PlaceholderColor" Value="{StaticResource Gray500}" />
|
||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
||||
<Setter Property="FontFamily" Value="OpenSansRegular" />
|
||||
<Setter Property="FontSize" Value="14" />
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Shadow">
|
||||
<Setter Property="Radius" Value="15" />
|
||||
<Setter Property="Opacity" Value="0.5" />
|
||||
<Setter Property="Brush" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource White}}" />
|
||||
<Setter Property="Offset" Value="10,10" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Slider">
|
||||
<Setter Property="MinimumTrackColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
|
||||
<Setter Property="MaximumTrackColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray600}}" />
|
||||
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="MinimumTrackColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}"/>
|
||||
<Setter Property="MaximumTrackColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}"/>
|
||||
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}"/>
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="SwipeItem">
|
||||
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Switch">
|
||||
<Setter Property="OnColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
|
||||
<Setter Property="ThumbColor" Value="{StaticResource White}" />
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="OnColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="On">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="OnColor" Value="{AppThemeBinding Light={StaticResource Secondary}, Dark={StaticResource Gray200}}" />
|
||||
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Off">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Gray400}, Dark={StaticResource Gray500}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="TimePicker">
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
|
||||
<Setter Property="TextColor" Value="{DynamicResource UlColorText}" />
|
||||
<Setter Property="BackgroundColor" Value="{DynamicResource UlColorSurface}" />
|
||||
<Setter Property="FontFamily" Value="{StaticResource UlTypeFamilySans}" />
|
||||
<Setter Property="FontSize" Value="{StaticResource UlTypeBodySize}" />
|
||||
<Setter Property="MinimumHeightRequest" Value="{StaticResource UlTouchMinimum}" />
|
||||
<Setter Property="MinimumWidthRequest" Value="{StaticResource UlTouchMinimum}" />
|
||||
</Style>
|
||||
<Style TargetType="SearchBar">
|
||||
<Setter Property="TextColor" Value="{DynamicResource UlColorText}" />
|
||||
<Setter Property="PlaceholderColor" Value="{DynamicResource UlColorTextMuted}" />
|
||||
<Setter Property="CancelButtonColor" Value="{DynamicResource UlColorPrimary}" />
|
||||
<Setter Property="BackgroundColor" Value="{DynamicResource UlColorSurface}" />
|
||||
<Setter Property="FontFamily" Value="{StaticResource UlTypeFamilySans}" />
|
||||
<Setter Property="FontSize" Value="{StaticResource UlTypeBodySize}" />
|
||||
<Setter Property="MinimumHeightRequest" Value="{StaticResource UlTouchMinimum}" />
|
||||
</Style>
|
||||
<Style TargetType="CheckBox">
|
||||
<Setter Property="Color" Value="{DynamicResource UlColorPrimary}" />
|
||||
<Setter Property="MinimumHeightRequest" Value="{StaticResource UlTouchMinimum}" />
|
||||
<Setter Property="MinimumWidthRequest" Value="{StaticResource UlTouchMinimum}" />
|
||||
</Style>
|
||||
<Style TargetType="RadioButton">
|
||||
<Setter Property="TextColor" Value="{DynamicResource UlColorText}" />
|
||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
||||
<Setter Property="FontFamily" Value="OpenSansRegular"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
<Setter Property="FontFamily" Value="{StaticResource UlTypeFamilySans}" />
|
||||
<Setter Property="FontSize" Value="{StaticResource UlTypeBodySize}" />
|
||||
<Setter Property="MinimumHeightRequest" Value="{StaticResource UlTouchMinimum}" />
|
||||
<Setter Property="MinimumWidthRequest" Value="{StaticResource UlTouchMinimum}" />
|
||||
</Style>
|
||||
|
||||
<!--
|
||||
<Style TargetType="TitleBar">
|
||||
<Setter Property="MinimumHeightRequest" Value="32"/>
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="TitleActiveStates">
|
||||
<VisualState x:Name="TitleBarTitleActive">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
||||
<Setter Property="ForegroundColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="TitleBarTitleInactive">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
|
||||
<Setter Property="ForegroundColor" Value="{AppThemeBinding Light={StaticResource Gray400}, Dark={StaticResource Gray500}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
<Style TargetType="Switch">
|
||||
<Setter Property="OnColor" Value="{DynamicResource UlColorPrimary}" />
|
||||
<Setter Property="ThumbColor" Value="{DynamicResource UlColorSurface}" />
|
||||
<Setter Property="MinimumHeightRequest" Value="{StaticResource UlTouchMinimum}" />
|
||||
<Setter Property="MinimumWidthRequest" Value="{StaticResource UlTouchMinimum}" />
|
||||
</Style>
|
||||
-->
|
||||
|
||||
<Style TargetType="Page" ApplyToDerivedTypes="True">
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource OffBlack}}" />
|
||||
<Style TargetType="Slider">
|
||||
<Setter Property="MinimumTrackColor" Value="{DynamicResource UlColorPrimary}" />
|
||||
<Setter Property="MaximumTrackColor" Value="{DynamicResource UlColorBorder}" />
|
||||
<Setter Property="ThumbColor" Value="{DynamicResource UlColorPrimary}" />
|
||||
<Setter Property="MinimumHeightRequest" Value="{StaticResource UlTouchMinimum}" />
|
||||
</Style>
|
||||
<Style TargetType="ProgressBar">
|
||||
<Setter Property="ProgressColor" Value="{DynamicResource UlColorPrimary}" />
|
||||
</Style>
|
||||
<Style TargetType="RefreshView">
|
||||
<Setter Property="RefreshColor" Value="{DynamicResource UlColorPrimary}" />
|
||||
</Style>
|
||||
<Style TargetType="ListView">
|
||||
<Setter Property="SeparatorColor" Value="{DynamicResource UlColorBorder}" />
|
||||
<Setter Property="RefreshControlColor" Value="{DynamicResource UlColorPrimary}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Shell" ApplyToDerivedTypes="True">
|
||||
<Setter Property="Shell.BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource OffBlack}}" />
|
||||
<Setter Property="Shell.ForegroundColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource SecondaryDarkText}}" />
|
||||
<Setter Property="Shell.TitleColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource SecondaryDarkText}}" />
|
||||
<Setter Property="Shell.DisabledColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray950}}" />
|
||||
<Setter Property="Shell.UnselectedColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray200}}" />
|
||||
<Setter Property="Shell.BackgroundColor" Value="{DynamicResource UlColorSurfaceStrong}" />
|
||||
<Setter Property="Shell.ForegroundColor" Value="{DynamicResource UlColorOnStrong}" />
|
||||
<Setter Property="Shell.TitleColor" Value="{DynamicResource UlColorOnStrong}" />
|
||||
<Setter Property="Shell.DisabledColor" Value="{DynamicResource UlColorDisabled}" />
|
||||
<Setter Property="Shell.UnselectedColor" Value="{DynamicResource UlColorBorder}" />
|
||||
<Setter Property="Shell.NavBarHasShadow" Value="False" />
|
||||
<Setter Property="Shell.TabBarBackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
|
||||
<Setter Property="Shell.TabBarForegroundColor" Value="{AppThemeBinding Light={StaticResource Magenta}, Dark={StaticResource White}}" />
|
||||
<Setter Property="Shell.TabBarTitleColor" Value="{AppThemeBinding Light={StaticResource Magenta}, Dark={StaticResource White}}" />
|
||||
<Setter Property="Shell.TabBarUnselectedColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
|
||||
<Setter Property="Shell.TabBarBackgroundColor" Value="{DynamicResource UlColorSurfaceStrong}" />
|
||||
<Setter Property="Shell.TabBarForegroundColor" Value="{DynamicResource UlColorOnStrong}" />
|
||||
<Setter Property="Shell.TabBarTitleColor" Value="{DynamicResource UlColorOnStrong}" />
|
||||
<Setter Property="Shell.TabBarUnselectedColor" Value="{DynamicResource UlColorBorder}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="NavigationPage">
|
||||
<Setter Property="BarBackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource OffBlack}}" />
|
||||
<Setter Property="BarTextColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource White}}" />
|
||||
<Setter Property="IconColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource White}}" />
|
||||
<Setter Property="BarBackgroundColor" Value="{DynamicResource UlColorSurfaceStrong}" />
|
||||
<Setter Property="BarTextColor" Value="{DynamicResource UlColorOnStrong}" />
|
||||
<Setter Property="IconColor" Value="{DynamicResource UlColorOnStrong}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="TabbedPage">
|
||||
<Setter Property="BarBackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Gray950}}" />
|
||||
<Setter Property="BarTextColor" Value="{AppThemeBinding Light={StaticResource Magenta}, Dark={StaticResource White}}" />
|
||||
<Setter Property="UnselectedTabColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray950}}" />
|
||||
<Setter Property="SelectedTabColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" />
|
||||
<Setter Property="BarBackgroundColor" Value="{DynamicResource UlColorSurfaceStrong}" />
|
||||
<Setter Property="BarTextColor" Value="{DynamicResource UlColorOnStrong}" />
|
||||
<Setter Property="UnselectedTabColor" Value="{DynamicResource UlColorBorder}" />
|
||||
<Setter Property="SelectedTabColor" Value="{DynamicResource UlColorOnStrong}" />
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
|
||||
38
FieldLogger/Resources/Styles/ThemeManager.cs
Normal file
38
FieldLogger/Resources/Styles/ThemeManager.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
namespace FieldLogger.Resources.Styles;
|
||||
|
||||
public enum UlThemeMode
|
||||
{
|
||||
Default,
|
||||
Sunlight,
|
||||
}
|
||||
|
||||
/// <summary>Applies generated semantic colors. Call on the UI thread after app resources initialize.</summary>
|
||||
public static class ThemeManager
|
||||
{
|
||||
private static readonly string[] SemanticColors =
|
||||
[
|
||||
"Canvas", "Surface", "SurfaceRaised", "SurfaceStrong", "Text", "TextMuted",
|
||||
"Primary", "PrimaryPressed", "Accent", "Border", "Focus", "Map", "Success",
|
||||
"Warning", "Error", "Neutral", "Disabled", "OnStrong", "OnPrimary", "OnAccent",
|
||||
];
|
||||
|
||||
public static UlThemeMode Current { get; private set; } = UlThemeMode.Default;
|
||||
|
||||
public static void Apply(UlThemeMode mode)
|
||||
{
|
||||
var resources = Application.Current?.Resources
|
||||
?? throw new InvalidOperationException("Application resources are not initialized.");
|
||||
var prefix = mode == UlThemeMode.Sunlight ? "UlSunlightColor" : "UlDefaultColor";
|
||||
|
||||
foreach (var name in SemanticColors)
|
||||
{
|
||||
if (!resources.TryGetValue($"{prefix}{name}", out var value) || value is not Color color)
|
||||
{
|
||||
throw new InvalidOperationException($"Generated theme token {prefix}{name} is missing.");
|
||||
}
|
||||
resources[$"UlColor{name}"] = color;
|
||||
resources[$"UlBrush{name}"] = new SolidColorBrush(color);
|
||||
}
|
||||
Current = mode;
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,16 @@ public sealed partial class HomeViewModel : ObservableObject
|
||||
[ObservableProperty]
|
||||
private string _syncStatus = "";
|
||||
|
||||
public bool HasNoActiveJob => !HasActiveJob;
|
||||
|
||||
public string ActiveJobPointSummary => PointCount == 1
|
||||
? "1 point saved locally"
|
||||
: $"{PointCount} points saved locally";
|
||||
|
||||
public string CaptureReadinessText => HasActiveJob
|
||||
? "READY · Press LOG on the locating receiver"
|
||||
: "BLOCKED · Choose or create an active job first";
|
||||
|
||||
public ObservableCollection<LoggedPoint> RecentPoints { get; } = new();
|
||||
|
||||
public HomeViewModel(DeviceConnectionManager manager, MaglinkService gps,
|
||||
@@ -149,6 +159,15 @@ public sealed partial class HomeViewModel : ObservableObject
|
||||
PointCount++;
|
||||
}
|
||||
|
||||
partial void OnHasActiveJobChanged(bool value)
|
||||
{
|
||||
OnPropertyChanged(nameof(HasNoActiveJob));
|
||||
OnPropertyChanged(nameof(CaptureReadinessText));
|
||||
}
|
||||
|
||||
partial void OnPointCountChanged(int value) =>
|
||||
OnPropertyChanged(nameof(ActiveJobPointSummary));
|
||||
|
||||
private async void OnPacketIgnoredNoJob(object? sender, EventArgs e)
|
||||
{
|
||||
await Shell.Current.DisplayAlert("No Active Job",
|
||||
|
||||
@@ -12,13 +12,28 @@ public sealed partial class JobListItem : ObservableObject
|
||||
public required Job Job { get; init; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(JobSummary))]
|
||||
[NotifyPropertyChangedFor(nameof(DeleteDescription))]
|
||||
[NotifyPropertyChangedFor(nameof(AccessibilityDescription))]
|
||||
private int _pointCount;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(ActiveStatusLabel))]
|
||||
[NotifyPropertyChangedFor(nameof(ActiveActionLabel))]
|
||||
[NotifyPropertyChangedFor(nameof(ActiveActionDescription))]
|
||||
[NotifyPropertyChangedFor(nameof(AccessibilityDescription))]
|
||||
private bool _isActive;
|
||||
|
||||
public string Name => Job.Name;
|
||||
public string CreatedLabel => Job.CreatedUtc.ToLocalTime().ToString("g");
|
||||
public string ActiveStatusLabel => IsActive ? "ACTIVE JOB" : "NOT ACTIVE";
|
||||
public string ActiveActionLabel => IsActive ? "Active" : "Set active";
|
||||
public string JobSummary => $"Created {CreatedLabel} · {PointCount} {(PointCount == 1 ? "point" : "points")}";
|
||||
public string ActiveActionDescription => IsActive
|
||||
? $"{Name} is already the active job"
|
||||
: $"Make {Name} the active capture job";
|
||||
public string DeleteDescription => $"Delete {Name} and its {PointCount} saved points";
|
||||
public string AccessibilityDescription => $"{Name}. {ActiveStatusLabel}. {JobSummary}.";
|
||||
}
|
||||
|
||||
public sealed partial class JobsViewModel : ObservableObject
|
||||
@@ -37,6 +52,7 @@ public sealed partial class JobsViewModel : ObservableObject
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public async Task RefreshAsync()
|
||||
{
|
||||
IsBusy = true;
|
||||
|
||||
@@ -16,10 +16,10 @@ public sealed partial class MapViewModel : ObservableObject
|
||||
private int _jobId;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _jobName = "";
|
||||
private string _jobName = "Active job map";
|
||||
|
||||
[ObservableProperty]
|
||||
private string _statusText = "";
|
||||
private string _statusText = "Loading locally saved points…";
|
||||
|
||||
public SettingsService Settings => _settings;
|
||||
|
||||
@@ -35,7 +35,7 @@ public sealed partial class MapViewModel : ObservableObject
|
||||
var jobId = JobId > 0 ? JobId : _settings.ActiveJobId;
|
||||
if (jobId is null)
|
||||
{
|
||||
JobName = "";
|
||||
JobName = "No active job";
|
||||
StatusText = "No job selected. Create or activate a job to see its points.";
|
||||
return new List<LoggedPoint>();
|
||||
}
|
||||
|
||||
@@ -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">
|
||||
|
||||
<!-- 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}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Live GNSS fix -->
|
||||
<Border StrokeThickness="0" Background="{AppThemeBinding Light=#F2F2F7, Dark=#1C1C1E}" StrokeShape="RoundRectangle 12" Padding="12">
|
||||
<VerticalStackLayout Padding="16" Spacing="16">
|
||||
<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" />
|
||||
<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>
|
||||
</Border>
|
||||
|
||||
<!-- Active job -->
|
||||
<Border StrokeThickness="0" Background="{AppThemeBinding Light=#F2F2F7, Dark=#1C1C1E}" StrokeShape="RoundRectangle 12" Padding="12">
|
||||
<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>
|
||||
<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>
|
||||
<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" />
|
||||
</Border>
|
||||
|
||||
<!-- 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>
|
||||
|
||||
<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" 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="{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>
|
||||
|
||||
@@ -5,37 +5,64 @@
|
||||
xmlns:models="clr-namespace:FieldLogger.Models"
|
||||
x:Class="FieldLogger.Views.JobDetailPage"
|
||||
x:DataType="vm:JobDetailViewModel"
|
||||
Title="{Binding JobName}">
|
||||
<ContentPage.ToolbarItems>
|
||||
<ToolbarItem Text="Map" Command="{Binding ViewMapCommand}" />
|
||||
</ContentPage.ToolbarItems>
|
||||
Title="{Binding JobName}"
|
||||
BackgroundColor="{DynamicResource UlColorCanvas}">
|
||||
<Grid RowDefinitions="Auto,*" Padding="16" RowSpacing="16">
|
||||
<Border Style="{StaticResource UlCard}" BackgroundColor="{DynamicResource UlColorSurfaceRaised}"
|
||||
Stroke="{DynamicResource UlColorBorder}" StrokeShape="RoundRectangle 12" Padding="16">
|
||||
<Grid RowDefinitions="Auto,Auto" ColumnDefinitions="*,Auto" RowSpacing="6" ColumnSpacing="12">
|
||||
<VerticalStackLayout>
|
||||
<Label Text="JOB DETAIL" FontSize="14" FontAttributes="Bold" CharacterSpacing="1.5"
|
||||
TextColor="{DynamicResource UlColorPrimary}" />
|
||||
<Label Text="{Binding JobName}" Style="{StaticResource UlPageTitle}"
|
||||
TextColor="{DynamicResource UlColorText}" LineBreakMode="TailTruncation"
|
||||
SemanticProperties.HeadingLevel="Level1" />
|
||||
</VerticalStackLayout>
|
||||
<Button Grid.Column="1" Style="{StaticResource UlButtonSecondary}"
|
||||
Text="View map" Command="{Binding ViewMapCommand}"
|
||||
MinimumHeightRequest="{StaticResource UlTouchMinimum}" MinimumWidthRequest="96"
|
||||
SemanticProperties.Description="View this job's captured points on the map" />
|
||||
<Label Grid.Row="1" Grid.ColumnSpan="2" FontSize="16"
|
||||
TextColor="{DynamicResource UlColorTextMuted}"
|
||||
Text="{Binding PointCount, StringFormat='{0} locally logged points'}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<Grid RowDefinitions="Auto,*" Padding="16" RowSpacing="8">
|
||||
<Label Grid.Row="0" FontSize="13" TextColor="Gray"
|
||||
Text="{Binding PointCount, StringFormat='{0} logged points'}" />
|
||||
|
||||
<CollectionView Grid.Row="1" ItemsSource="{Binding Points}">
|
||||
<CollectionView Grid.Row="1" ItemsSource="{Binding Points}"
|
||||
SemanticProperties.Description="Captured points for this job">
|
||||
<CollectionView.EmptyView>
|
||||
<Label Text="No points logged for this job yet." TextColor="Gray" Margin="8" />
|
||||
<Border Style="{StaticResource UlCard}" BackgroundColor="{DynamicResource UlColorSurfaceRaised}"
|
||||
Stroke="{DynamicResource UlColorBorder}"
|
||||
StrokeShape="RoundRectangle 12" Padding="24">
|
||||
<VerticalStackLayout Spacing="8">
|
||||
<Label Text="No captures for this job" Style="{StaticResource UlEmptyStateTitle}"
|
||||
HorizontalTextAlignment="Center" TextColor="{DynamicResource UlColorText}" />
|
||||
<Label Text="Return Home and press LOG on the receiver when the job is active."
|
||||
Style="{StaticResource UlEmptyStateBody}"
|
||||
FontSize="16" HorizontalTextAlignment="Center"
|
||||
TextColor="{DynamicResource UlColorTextMuted}" />
|
||||
</VerticalStackLayout>
|
||||
</Border>
|
||||
</CollectionView.EmptyView>
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate x:DataType="models:LoggedPoint">
|
||||
<Border StrokeThickness="0" Background="{AppThemeBinding Light=#F2F2F7, Dark=#1C1C1E}"
|
||||
StrokeShape="RoundRectangle 10" Padding="12" Margin="0,4">
|
||||
<Grid ColumnDefinitions="*,Auto" RowDefinitions="Auto,Auto,Auto,Auto" RowSpacing="2">
|
||||
<Label Grid.Row="0" FontAttributes="Bold" FontSize="14">
|
||||
<Border Style="{StaticResource UlJobRow}" BackgroundColor="{DynamicResource UlColorSurfaceRaised}"
|
||||
Stroke="{DynamicResource UlColorBorder}" StrokeShape="RoundRectangle 12"
|
||||
Padding="16" Margin="0,0,0,12" MinimumHeightRequest="168">
|
||||
<Grid ColumnDefinitions="*,Auto" RowDefinitions="Auto,Auto,Auto,Auto" RowSpacing="8" ColumnSpacing="12">
|
||||
<Label FontSize="18" FontAttributes="Bold" TextColor="{DynamicResource UlColorText}">
|
||||
<Label.Text>
|
||||
<MultiBinding StringFormat="{}#{0} · {1} · {2} Hz">
|
||||
<MultiBinding StringFormat="{}Point #{0} · {1} · {2} Hz">
|
||||
<Binding Path="Id" />
|
||||
<Binding Path="Utility" Converter="{StaticResource UtilityName}" />
|
||||
<Binding Path="Frequency" />
|
||||
</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:g}'}" />
|
||||
|
||||
<Label Grid.Row="1" Grid.ColumnSpan="2" FontSize="12">
|
||||
<Label Grid.Row="1" Grid.ColumnSpan="2" FontSize="16"
|
||||
TextColor="{DynamicResource UlColorText}">
|
||||
<Label.Text>
|
||||
<MultiBinding StringFormat="Depth {0} · Current {1} · Signal {2} · Gain {3} dB">
|
||||
<Binding Path="DepthRaw" />
|
||||
@@ -45,8 +72,8 @@
|
||||
</MultiBinding>
|
||||
</Label.Text>
|
||||
</Label>
|
||||
|
||||
<Label Grid.Row="2" Grid.ColumnSpan="2" FontSize="12" FontFamily="Courier New">
|
||||
<Label Grid.Row="2" Grid.ColumnSpan="2" FontSize="16" FontFamily="{StaticResource UlTypeFamilyMono}"
|
||||
TextColor="{DynamicResource UlColorText}">
|
||||
<Label.Text>
|
||||
<MultiBinding StringFormat="{}{0:F8}, {1:F8}">
|
||||
<Binding Path="Latitude" />
|
||||
@@ -54,20 +81,22 @@
|
||||
</MultiBinding>
|
||||
</Label.Text>
|
||||
</Label>
|
||||
|
||||
<Label Grid.Row="3" FontSize="11" TextColor="Gray">
|
||||
<Label Grid.Row="3" FontSize="14" TextColor="{DynamicResource UlColorTextMuted}">
|
||||
<Label.Text>
|
||||
<MultiBinding StringFormat="{}{0} · H ±{1:F3} m · {2} sats">
|
||||
<MultiBinding StringFormat="{}{0} · H ±{1:F3} m · {2} satellites">
|
||||
<Binding Path="FixStatus" Converter="{StaticResource FixStatusName}" />
|
||||
<Binding Path="Hrms" />
|
||||
<Binding Path="SatellitesUsed" />
|
||||
</MultiBinding>
|
||||
</Label.Text>
|
||||
</Label>
|
||||
<Button Grid.Row="3" Grid.Column="1" Text="Delete" FontSize="11" Padding="8,2"
|
||||
BackgroundColor="Transparent" TextColor="IndianRed"
|
||||
<Button Grid.Row="3" Grid.Column="1" Style="{StaticResource UlButtonAccent}"
|
||||
Text="Delete point" MinimumHeightRequest="{StaticResource UlTouchMinimum}"
|
||||
BackgroundColor="{DynamicResource UlColorAccent}"
|
||||
TextColor="{DynamicResource UlColorOnAccent}"
|
||||
Command="{Binding DeletePointCommand, Source={RelativeSource AncestorType={x:Type vm:JobDetailViewModel}}}"
|
||||
CommandParameter="{Binding .}" />
|
||||
CommandParameter="{Binding .}"
|
||||
SemanticProperties.Description="Delete this locally saved point" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
|
||||
@@ -4,57 +4,91 @@
|
||||
xmlns:vm="clr-namespace:FieldLogger.ViewModels"
|
||||
x:Class="FieldLogger.Views.JobsPage"
|
||||
x:DataType="vm:JobsViewModel"
|
||||
Title="Jobs">
|
||||
<ContentPage.ToolbarItems>
|
||||
<ToolbarItem Text="New" Command="{Binding NewJobCommand}" />
|
||||
</ContentPage.ToolbarItems>
|
||||
|
||||
<Grid Padding="16">
|
||||
<CollectionView ItemsSource="{Binding Jobs}">
|
||||
<CollectionView.EmptyView>
|
||||
<VerticalStackLayout Spacing="8" VerticalOptions="Center">
|
||||
<Label Text="No jobs yet." TextColor="Gray" HorizontalOptions="Center" />
|
||||
<Button Text="Create First Job" Command="{Binding NewJobCommand}" HorizontalOptions="Center" />
|
||||
Title="Jobs"
|
||||
BackgroundColor="{DynamicResource UlColorCanvas}">
|
||||
<Grid RowDefinitions="Auto,Auto,*" Padding="16" RowSpacing="16">
|
||||
<VerticalStackLayout Spacing="4">
|
||||
<Label Text="FIELD WORK" FontSize="14" FontAttributes="Bold" CharacterSpacing="1.5"
|
||||
TextColor="{DynamicResource UlColorPrimary}" />
|
||||
<Label Text="Jobs" Style="{StaticResource UlPageTitle}"
|
||||
TextColor="{DynamicResource UlColorText}"
|
||||
SemanticProperties.HeadingLevel="Level1" />
|
||||
<Label Text="Choose the active job before capturing points."
|
||||
FontSize="16" TextColor="{DynamicResource UlColorTextMuted}" />
|
||||
</VerticalStackLayout>
|
||||
|
||||
<Button Grid.Row="1" Style="{StaticResource UlButtonPrimaryField}"
|
||||
Text="+ Create new job" Command="{Binding NewJobCommand}"
|
||||
MinimumHeightRequest="{StaticResource UlTouchComfortable}" FontSize="16" FontAttributes="Bold"
|
||||
SemanticProperties.Description="Create a new job and make it active" />
|
||||
|
||||
<RefreshView Grid.Row="2" Command="{Binding RefreshCommand}" IsRefreshing="{Binding IsBusy}">
|
||||
<CollectionView ItemsSource="{Binding Jobs}"
|
||||
SelectionMode="None"
|
||||
SemanticProperties.Description="Jobs available on this device">
|
||||
<CollectionView.EmptyView>
|
||||
<Border Style="{StaticResource UlCard}" BackgroundColor="{DynamicResource UlColorSurfaceRaised}"
|
||||
Stroke="{DynamicResource UlColorBorder}"
|
||||
StrokeShape="RoundRectangle 12" Padding="24">
|
||||
<VerticalStackLayout Spacing="8" VerticalOptions="Center">
|
||||
<Label Text="No jobs yet" Style="{StaticResource UlEmptyStateTitle}"
|
||||
HorizontalTextAlignment="Center" TextColor="{DynamicResource UlColorText}" />
|
||||
<Label Text="Create a job to establish the capture context."
|
||||
Style="{StaticResource UlEmptyStateBody}"
|
||||
FontSize="16" HorizontalTextAlignment="Center"
|
||||
TextColor="{DynamicResource UlColorTextMuted}" />
|
||||
<Button Style="{StaticResource UlButtonPrimary}"
|
||||
Text="Create first job" Command="{Binding NewJobCommand}"
|
||||
MinimumHeightRequest="{StaticResource UlTouchComfortable}" HorizontalOptions="Fill"
|
||||
SemanticProperties.Description="Create the first job" />
|
||||
</VerticalStackLayout>
|
||||
</Border>
|
||||
</CollectionView.EmptyView>
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:JobListItem">
|
||||
<Border StrokeThickness="0" Background="{AppThemeBinding Light=#F2F2F7, Dark=#1C1C1E}"
|
||||
StrokeShape="RoundRectangle 10" Padding="12" Margin="0,4">
|
||||
<Border Style="{StaticResource UlJobRow}" BackgroundColor="{DynamicResource UlColorSurfaceRaised}"
|
||||
Stroke="{DynamicResource UlColorBorder}"
|
||||
StrokeThickness="1" StrokeShape="RoundRectangle 12"
|
||||
Padding="16" Margin="0,0,0,12" MinimumHeightRequest="136"
|
||||
SemanticProperties.Description="{Binding AccessibilityDescription}"
|
||||
SemanticProperties.Hint="Double tap to open job details">
|
||||
<Border.GestureRecognizers>
|
||||
<TapGestureRecognizer
|
||||
Command="{Binding OpenCommand, Source={RelativeSource AncestorType={x:Type vm:JobsViewModel}}}"
|
||||
CommandParameter="{Binding .}" />
|
||||
</Border.GestureRecognizers>
|
||||
<Grid ColumnDefinitions="*,Auto,Auto" ColumnSpacing="8">
|
||||
<VerticalStackLayout Spacing="2">
|
||||
<HorizontalStackLayout Spacing="8">
|
||||
<Label Text="{Binding Name}" FontAttributes="Bold" />
|
||||
<Border IsVisible="{Binding IsActive}" Background="DodgerBlue"
|
||||
StrokeThickness="0" StrokeShape="RoundRectangle 6" Padding="6,1">
|
||||
<Label Text="ACTIVE" FontSize="10" TextColor="White" />
|
||||
<Grid RowDefinitions="Auto,Auto,Auto" ColumnDefinitions="*,Auto" RowSpacing="8" ColumnSpacing="12">
|
||||
<Label Text="{Binding Name}" FontSize="20" FontAttributes="Bold"
|
||||
TextColor="{DynamicResource UlColorText}" LineBreakMode="TailTruncation" />
|
||||
<Border Grid.Column="1" Style="{StaticResource UlStatusBadge}"
|
||||
BackgroundColor="{DynamicResource UlColorCanvas}"
|
||||
Stroke="{DynamicResource UlColorBorder}"
|
||||
StrokeShape="RoundRectangle 8" Padding="8,4">
|
||||
<Label Text="{Binding ActiveStatusLabel}" FontSize="14" FontAttributes="Bold"
|
||||
TextColor="{DynamicResource UlColorText}" />
|
||||
</Border>
|
||||
</HorizontalStackLayout>
|
||||
<Label FontSize="12" TextColor="Gray">
|
||||
<Label.Text>
|
||||
<MultiBinding StringFormat="{}{0} · {1} points">
|
||||
<Binding Path="CreatedLabel" />
|
||||
<Binding Path="PointCount" />
|
||||
</MultiBinding>
|
||||
</Label.Text>
|
||||
</Label>
|
||||
</VerticalStackLayout>
|
||||
<Button Grid.Column="1" Text="Set Active" FontSize="12" Padding="10,4" VerticalOptions="Center"
|
||||
<Label Grid.Row="1" Grid.ColumnSpan="2" Text="{Binding JobSummary}"
|
||||
FontSize="16" TextColor="{DynamicResource UlColorTextMuted}" />
|
||||
<Grid Grid.Row="2" Grid.ColumnSpan="2" ColumnDefinitions="*,*" ColumnSpacing="8">
|
||||
<Button Style="{StaticResource UlButtonSecondary}"
|
||||
Text="{Binding ActiveActionLabel}"
|
||||
IsEnabled="{Binding IsActive, Converter={StaticResource InvertBool}}"
|
||||
Command="{Binding SetActiveCommand, Source={RelativeSource AncestorType={x:Type vm:JobsViewModel}}}"
|
||||
CommandParameter="{Binding .}" />
|
||||
<Button Grid.Column="2" Text="✕" FontSize="12" Padding="10,4" VerticalOptions="Center"
|
||||
BackgroundColor="IndianRed" TextColor="White"
|
||||
CommandParameter="{Binding .}" MinimumHeightRequest="{StaticResource UlTouchMinimum}"
|
||||
SemanticProperties.Description="{Binding ActiveActionDescription}" />
|
||||
<Button Grid.Column="1" Style="{StaticResource UlButtonAccent}"
|
||||
Text="Delete job"
|
||||
BackgroundColor="{DynamicResource UlColorAccent}"
|
||||
TextColor="{DynamicResource UlColorOnAccent}"
|
||||
Command="{Binding DeleteCommand, Source={RelativeSource AncestorType={x:Type vm:JobsViewModel}}}"
|
||||
CommandParameter="{Binding .}" />
|
||||
CommandParameter="{Binding .}" MinimumHeightRequest="{StaticResource UlTouchMinimum}"
|
||||
SemanticProperties.Description="{Binding DeleteDescription}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</CollectionView.ItemTemplate>
|
||||
</CollectionView>
|
||||
</RefreshView>
|
||||
</Grid>
|
||||
</ContentPage>
|
||||
|
||||
@@ -4,10 +4,32 @@
|
||||
xmlns:vm="clr-namespace:FieldLogger.ViewModels"
|
||||
x:Class="FieldLogger.Views.MapPage"
|
||||
x:DataType="vm:MapViewModel"
|
||||
Title="Map">
|
||||
Title="Map"
|
||||
BackgroundColor="{DynamicResource UlColorMap}">
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<Label Grid.Row="0" Text="{Binding StatusText}" FontSize="12" TextColor="Gray" Padding="12,6" />
|
||||
<Border Style="{StaticResource UlCard}" Margin="12" Padding="16" BackgroundColor="{DynamicResource UlColorSurfaceRaised}"
|
||||
Stroke="{DynamicResource UlColorBorder}" StrokeShape="RoundRectangle 12"
|
||||
ZIndex="1">
|
||||
<Grid RowDefinitions="Auto,Auto" ColumnDefinitions="*,Auto" RowSpacing="4" ColumnSpacing="12">
|
||||
<VerticalStackLayout>
|
||||
<Label Text="LIVE MAP" FontSize="14" FontAttributes="Bold" CharacterSpacing="1.5"
|
||||
TextColor="{DynamicResource UlColorPrimary}" />
|
||||
<Label Text="{Binding JobName, TargetNullValue='No active job'}"
|
||||
Style="{StaticResource UlSectionTitle}" TextColor="{DynamicResource UlColorText}"
|
||||
SemanticProperties.HeadingLevel="Level1" />
|
||||
</VerticalStackLayout>
|
||||
<Button Grid.Column="1" Style="{StaticResource UlButtonSecondary}"
|
||||
Text="Refresh" Clicked="OnRefreshClicked"
|
||||
MinimumHeightRequest="{StaticResource UlTouchMinimum}" MinimumWidthRequest="88"
|
||||
SemanticProperties.Description="Refresh captured points on the map" />
|
||||
<Label Grid.Row="1" Grid.ColumnSpan="2" Text="{Binding StatusText}" FontSize="14"
|
||||
TextColor="{DynamicResource UlColorTextMuted}"
|
||||
SemanticProperties.Description="Current map data status" />
|
||||
</Grid>
|
||||
</Border>
|
||||
<!-- Populated in code-behind: native Map control on iOS/Android/macOS, Google Maps WebView on Windows. -->
|
||||
<ContentView Grid.Row="1" x:Name="MapHost" />
|
||||
<ContentView Grid.RowSpan="2" x:Name="MapHost"
|
||||
BackgroundColor="{DynamicResource UlColorMap}"
|
||||
SemanticProperties.Description="Map of locally captured points for the selected job" />
|
||||
</Grid>
|
||||
</ContentPage>
|
||||
|
||||
@@ -32,6 +32,16 @@ public partial class MapPage : ContentPage
|
||||
protected override async void OnAppearing()
|
||||
{
|
||||
base.OnAppearing();
|
||||
await RefreshMapAsync();
|
||||
}
|
||||
|
||||
private async void OnRefreshClicked(object? sender, EventArgs e)
|
||||
{
|
||||
await RefreshMapAsync();
|
||||
}
|
||||
|
||||
private async Task RefreshMapAsync()
|
||||
{
|
||||
await EnsureMapCreatedAsync();
|
||||
var points = await _viewModel.LoadPointsAsync();
|
||||
ShowPoints(points);
|
||||
|
||||
130
tests/FieldLogger.Tests/Sprint3UiContractTests.cs
Normal file
130
tests/FieldLogger.Tests/Sprint3UiContractTests.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml.Linq;
|
||||
using Xunit;
|
||||
|
||||
namespace FieldLogger.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Headless guardrails for the Sprint 3 MAUI screen integration. These deliberately inspect
|
||||
/// XAML source so the QA gate can verify token use and accessibility basics without a MAUI
|
||||
/// simulator or device workload.
|
||||
/// </summary>
|
||||
public sealed class Sprint3UiContractTests
|
||||
{
|
||||
private static readonly string[] MigratedScreens =
|
||||
[
|
||||
"FieldLogger/Views/HomePage.xaml",
|
||||
"FieldLogger/Views/JobsPage.xaml",
|
||||
"FieldLogger/Views/JobDetailPage.xaml",
|
||||
"FieldLogger/Views/MapPage.xaml",
|
||||
];
|
||||
|
||||
[Fact]
|
||||
public void Migrated_screens_use_only_semantic_color_resources()
|
||||
{
|
||||
var hardCodedColor = new Regex(@"#[0-9a-fA-F]{3,8}\b", RegexOptions.CultureInvariant);
|
||||
foreach (var path in MigratedScreens)
|
||||
{
|
||||
var text = File.ReadAllText(FromRoot(path));
|
||||
Assert.False(hardCodedColor.IsMatch(text), $"Page-level color literal found in {path}");
|
||||
Assert.DoesNotContain("TextColor=\"Gray\"", text, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.DoesNotContain("DodgerBlue", text, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.DoesNotContain("IndianRed", text, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Every_referenced_Survey_Teal_token_exists_in_generated_resources()
|
||||
{
|
||||
var resourceText = string.Concat(
|
||||
File.ReadAllText(FromRoot("FieldLogger/Resources/Styles/GeneratedTokens.xaml")),
|
||||
File.ReadAllText(FromRoot("FieldLogger/Resources/Styles/Styles.xaml")));
|
||||
var defined = Regex.Matches(resourceText, "x:Key=\\\"(?<key>Ul[^\\\"]+)\\\"")
|
||||
.Select(match => match.Groups["key"].Value)
|
||||
.ToHashSet(StringComparer.Ordinal);
|
||||
var resourceReference = new Regex(@"\{(?:Static|Dynamic)Resource (?<key>Ul[^}\s]+)\}");
|
||||
|
||||
foreach (var path in MigratedScreens.Append("FieldLogger/AppShell.xaml"))
|
||||
{
|
||||
foreach (Match match in resourceReference.Matches(File.ReadAllText(FromRoot(path))))
|
||||
{
|
||||
var key = match.Groups["key"].Value;
|
||||
Assert.Contains(key, defined);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void App_loads_generated_tokens_before_shared_component_styles()
|
||||
{
|
||||
var app = File.ReadAllText(FromRoot("FieldLogger/App.xaml"));
|
||||
var generatedIndex = app.IndexOf("GeneratedTokens.xaml", StringComparison.Ordinal);
|
||||
var stylesIndex = app.IndexOf("Styles.xaml", StringComparison.Ordinal);
|
||||
Assert.True(generatedIndex >= 0, "App.xaml must merge GeneratedTokens.xaml.");
|
||||
Assert.True(stylesIndex > generatedIndex, "Generated tokens must load before component styles.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Migrated_screens_consume_shared_component_styles()
|
||||
{
|
||||
var migrated = string.Concat(MigratedScreens.Select(path => File.ReadAllText(FromRoot(path))));
|
||||
Assert.Contains("UlCard", migrated, StringComparison.Ordinal);
|
||||
Assert.Contains("UlJobRow", migrated, StringComparison.Ordinal);
|
||||
Assert.Contains("UlStatusBadge", migrated, StringComparison.Ordinal);
|
||||
Assert.Contains("UlButtonSecondary", migrated, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Every_page_button_declares_at_least_the_minimum_touch_target()
|
||||
{
|
||||
var accepted = new[]
|
||||
{
|
||||
"{StaticResource UlTouchMinimum}",
|
||||
"{StaticResource UlTouchComfortable}",
|
||||
"{StaticResource UlTouchPrimary}",
|
||||
};
|
||||
|
||||
foreach (var path in MigratedScreens)
|
||||
{
|
||||
var document = XDocument.Load(FromRoot(path));
|
||||
foreach (var button in document.Descendants().Where(e => e.Name.LocalName == "Button"))
|
||||
{
|
||||
var target = button.Attribute("MinimumHeightRequest")?.Value;
|
||||
Assert.Contains(target, accepted);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Production_shell_does_not_expose_Debug_as_a_primary_tab()
|
||||
{
|
||||
var shell = File.ReadAllText(FromRoot("FieldLogger/AppShell.xaml"));
|
||||
Assert.DoesNotContain("Title=\"Debug\"", shell, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("views:DebugPage", shell, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Home_explains_real_receiver_capture_without_inventing_an_app_command()
|
||||
{
|
||||
var home = File.ReadAllText(FromRoot("FieldLogger/Views/HomePage.xaml"));
|
||||
var state = File.ReadAllText(FromRoot("FieldLogger/ViewModels/HomeViewModel.cs"));
|
||||
Assert.Contains("CAPTURE FROM RECEIVER", home, StringComparison.Ordinal);
|
||||
Assert.Contains("Press LOG on the locating receiver", state, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("CaptureCommand", home, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
private static string FromRoot(string relativePath) => Path.Combine(FindRepositoryRoot(), relativePath);
|
||||
|
||||
private static string FindRepositoryRoot()
|
||||
{
|
||||
for (var directory = new DirectoryInfo(AppContext.BaseDirectory);
|
||||
directory is not null;
|
||||
directory = directory.Parent)
|
||||
{
|
||||
if (File.Exists(Path.Combine(directory.FullName, "FieldLogger.sln")))
|
||||
return directory.FullName;
|
||||
}
|
||||
|
||||
throw new DirectoryNotFoundException("Could not find the FieldLogger repository root.");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user