Add economic indicatros

This commit is contained in:
2026-02-19 09:09:56 -05:00
parent 315cf51da4
commit 89b0ee98ef
5 changed files with 432 additions and 0 deletions

View File

@@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace MarketData.MarketDataModel
{
public class EconomicIndicators : List<EconomicIndicator>
{
public EconomicIndicators()
{
}
public EconomicIndicators(List<EconomicIndicator> economicIndicators)
{
foreach(EconomicIndicator economicIndicator in economicIndicators)
{
Add(economicIndicator);
}
}
public List<Int32> GetYears()
{
if(0==Count)return null;
List<Int32> years = (from EconomicIndicator economicIndicator in this select economicIndicator.Year).Distinct().ToList();
years.Sort();
return years;
}
public Dictionary<String,EconomicIndicators> GetDictionary()
{
Dictionary<String,EconomicIndicators> dictionary=new Dictionary<String,EconomicIndicators>();
if(0==Count)return null;
for (int index = 0; index < Count; index++)
{
EconomicIndicator economicIndicator=this[index];
if(!dictionary.ContainsKey(economicIndicator.CountryCode))
{
List<EconomicIndicator> list=new List<EconomicIndicator>();
dictionary.Add(economicIndicator.CountryCode,new EconomicIndicators());
}
EconomicIndicators economicIndicators=dictionary[economicIndicator.CountryCode];
economicIndicators.Add(economicIndicator);
}
List<String> keys=new List<String>(dictionary.Keys);
foreach(String key in keys)
{
dictionary[key].Sort(new EconomicIndicatorByYear());
}
return dictionary;
}
}
public class EconomicIndicatorByYear : IComparer<EconomicIndicator>
{
public int Compare(EconomicIndicator p1,EconomicIndicator p2)
{
return p1.Year.CompareTo(p2.Year);
}
}
public class EconomicIndicator
{
public String Source{get;set;}
public String CountryName{get;set;}
public String CountryCode{get;set;}
public String IndicatorName{get;set;}
public String IndicatorCode{get;set;}
public double IndicatorValue{get;set;}
public int Year{get;set;}
}
}

View File

@@ -0,0 +1,133 @@
using DataDisplay.Common;
using DataDisplay.DataSource;
using DataDisplay.Graph;
using DataDisplay.Renderers;
using MarketData.Utils;
using SkiaSharp;
using System;
namespace Navigator.Renderers
{
public class EconomicIndicatorsRenderer : IRenderer
{
private SKPaint paintSeries=new SKPaint{Style=SKPaintStyle.StrokeAndFill,Color=new SKColor((uint)SKColors.Black),StrokeWidth=5f};
private LineGraph economicIndicatorsLineGraph;
public event EventHandler RefreshRequested;
public void Refresh()
{
RefreshRequested?.Invoke(this, EventArgs.Empty);
}
public double XDataExtent{get;set;}
public double XDataExtentMin{get;set;}
public double XRange{get{return XDataExtent-XDataExtentMin;}}
public double YDataExtent{get;set;}
public double YDataExtentMin{get;set;}
public double YRange{get{return YDataExtent-YDataExtentMin;}}
public CompositeDataSource EconomicIndicatorElements
{
set
{
if(null==economicIndicatorsLineGraph)economicIndicatorsLineGraph=new LineGraph(paintSeries,value);
else economicIndicatorsLineGraph.SetDataSource(value);
}
}
public bool AnyData()
{
if(null==economicIndicatorsLineGraph)return false;
return true;
}
public void SetColorRed()
{
if(!AnyData())return;
paintSeries.Color=new SKColor((uint)SKColors.Red);
}
public void SetColorGreen()
{
if(!AnyData())return;
paintSeries.Color=new SKColor((uint)SKColors.Green);
}
public void SetColorBlack()
{
if(!AnyData())return;
paintSeries.Color=new SKColor((uint)SKColors.Black);
}
// ************************************************************************************************************************************
// ********************************************************* R E N D E R E R *********************************************************
// ************************************************************************************************************************************
public void PaintSurface(SKSurface surface,SKImageInfo imageInfo)
{
SKCanvas canvas = surface.Canvas;
canvas.Clear();
if(!AnyData())return;
int width=imageInfo.Width;
int height=imageInfo.Height;
XDataExtent=GetXDataExtent();
YDataExtent=GetYDataExtent();
XDataExtentMin=GetXDataExtentMin();
YDataExtentMin=GetYDataExtentMin();
PointMapping pointMapping=new PointMapping(width,height,XDataExtent,XDataExtentMin,YDataExtent,YDataExtentMin,80,50);
GridLines gridLines=new GridLines(10,10);
gridLines.AssignXDataType=GetXDataType;
gridLines.AssignGetYDataType=GetYDataType;
gridLines.AssignYDataFormatter=YDataFormatter;
gridLines.Render(canvas,pointMapping);
if(null!=economicIndicatorsLineGraph)economicIndicatorsLineGraph.Render(canvas,pointMapping);
}
private double GetXDataExtent()
{
if(null==economicIndicatorsLineGraph)return 0.00;
return economicIndicatorsLineGraph.GetXExtent();
}
private double GetYDataExtent()
{
if(null==economicIndicatorsLineGraph)return 0.00;
double maxDataExtent=economicIndicatorsLineGraph.GetYExtent();
return maxDataExtent;
}
// custom grid label formatter for the data along the left side of the chart. We know a-priori that this is of type double.
private String YDataFormatter(Object data)
{
Type dataType=data.GetType();
String strValue=Utility.FormatNumberConstrain((double)data);
return strValue;
}
private double GetXDataExtentMin()
{
if(null==economicIndicatorsLineGraph)return 0.00;
return economicIndicatorsLineGraph.GetXExtentMin();
}
private double GetYDataExtentMin()
{
if(null==economicIndicatorsLineGraph)return 0.00;
return economicIndicatorsLineGraph.GetYExtentMin();
}
private Type GetXDataType()
{
return typeof(DateTime);
}
private Type GetYDataType()
{
return typeof(double);
}
}
}

View File

@@ -0,0 +1,128 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows.Input;
using MarketData.MarketDataModel;
using MarketData.Service;
using Navigator.Core;
using DataDisplay.Renderers;
using Navigator.MarketDataModel;
using Navigator.Renderers;
namespace Navigator.ViewModels
{
public class EconomicIndicatorsViewModel : WorkspaceViewModel
{
private RelayCommand refreshCommand;
private bool isRefreshing = false;
private EconomicIndicatorsRenderer economicIndicatorsRenderer=new EconomicIndicatorsRenderer();
private String selectedCode;
private EconomicIndicators economicIndicators = default;
private String chartTitle;
private ObservableCollection<String> codeCollection;
private bool showActivity = true;
public EconomicIndicatorsViewModel()
{
Title = "Consumer Price Index";
Initialize();
PropertyChanged += OnViewModelPropertyChanged;
}
private void OnViewModelPropertyChanged(object sender,PropertyChangedEventArgs eventArgs)
{
if (eventArgs.PropertyName.Equals("SelectedCode"))
{
if (null == selectedCode) return;
HandleSelectedCodeRequest();
}
}
private void Initialize()
{
Task workerTask=Task.Factory.StartNew(()=>
{
IEnumerable<String> codes=null;
ServiceResult serviceResult=MarketDataServiceClient.GetInstance().GetDistinctEconomicIndicatorCodes();
if(serviceResult.Success)codes=(List<String>)serviceResult.ContextSpecificResult;
CodeCollection=new ObservableCollection<string>(codes);
});
workerTask.ContinueWith((continuation)=>
{
});
}
public void HandleSelectedCodeRequest()
{
ServiceResult serviceResult = null;
IsBusy=true;
ShowActivity=!IsRefreshing;
Task workerTask = Task.Factory.StartNew(() =>
{
serviceResult = MarketDataServiceClient.GetInstance().GetGetEconomicIndicators(selectedCode);
if (serviceResult.Success)
{
ChartTitle = selectedCode;
economicIndicators = new EconomicIndicators((List<EconomicIndicator>)serviceResult.ContextSpecificResult);
if(null!=economicIndicators && economicIndicators.Count>0)
{
economicIndicatorsRenderer.EconomicIndicatorElements=EconomicIndicatorsModel.Elements(economicIndicators);
economicIndicatorsRenderer.SetColorBlack();
economicIndicatorsRenderer.Refresh();
}
}
});
workerTask.ContinueWith((TaskContinuationOptions) =>
{
IsBusy=false;
IsRefreshing=false;
ShowActivity=!IsRefreshing;
});
}
public ObservableCollection<String> CodeCollection
{
get { return codeCollection; }
set { SetProperty(ref codeCollection, value); }
}
public IRenderer Renderer
{
get{return economicIndicatorsRenderer;}
}
public String SelectedCode
{
get { return selectedCode; }
set { SetProperty(ref selectedCode, value); }
}
public String ChartTitle
{
get { return chartTitle; }
set { SetProperty(ref chartTitle, value); }
}
public bool IsRefreshing
{
get{return isRefreshing;}
set{SetProperty(ref isRefreshing,value);}
}
public bool ShowActivity
{
get {return showActivity;}
set {SetProperty(ref showActivity,value);}
}
public ICommand RefreshCommand
{
get
{
if(null==refreshCommand)
{
refreshCommand=new RelayCommand(param=>
{
HandleSelectedCodeRequest();
},param=>{return !IsRefreshing;});
}
return refreshCommand;
}
}
}
}

View File

@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:dd="clr-namespace:DataDisplay.Controls;assembly=DataDisplay"
xmlns:vm="clr-namespace:Navigator.ViewModels"
ControlTemplate="{StaticResource ActivityIndicatorTemplate}"
x:Class="Navigator.Views.EconomicIndicatorsPage">
<ContentPage.BindingContext>
<vm:EconomicIndicatorsViewModel />
</ContentPage.BindingContext>
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="FrameCardViewStyle" TargetType="Frame">
<Setter Property="CornerRadius" Value="5" />
<Setter Property="Margin" Value="5" />
<Setter Property="Padding" Value="5" />
<Setter Property="HorizontalOptions" Value="FillAndExpand" />
<Setter Property="OutlineColor" Value="LightGray" />
<Setter Property="BorderColor" Value="LightGray" />
<Setter Property="HasShadow" Value="True" />
</Style>
<Style x:Key="CenteredLabelStyle" TargetType="Label">
<Setter Property="FontSize" Value="12"/>
<Setter Property="FontAttributes" Value="Bold" />
<Setter Property="TextColor" Value="Black" />
<Setter Property="HorizontalTextAlignment" Value="Center" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<Grid BackgroundColor="White" Margin="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30*" />
<RowDefinition Height="70*" />
</Grid.RowDefinitions>
<Frame Grid.Row="0" Style="{StaticResource FrameCardViewStyle}">
<StackLayout Orientation="Horizontal">
<StackLayout Orientation="Vertical" >
<Label Text="Code" HorizontalTextAlignment="Left" FontSize="15">
</Label>
<ListView x:Name="listView" SeparatorVisibility="Default" ItemsSource="{Binding CodeCollection,Mode=TwoWay}" SelectedItem="{Binding SelectedCode,Mode=TwoWay}" >
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding .}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</StackLayout>
</Frame>
<Frame Grid.Row="1" Style="{StaticResource FrameCardViewStyle}">
<Grid Margin="1">
<Grid.RowDefinitions>
<RowDefinition Height="4*" />
<RowDefinition Height="4*" />
<RowDefinition Height="80*" />
</Grid.RowDefinitions>
<Label Grid.Row="1" Text="{Binding ChartTitle}" Style="{StaticResource CenteredLabelStyle}"></Label>
<RefreshView Grid.Row="2" IsRefreshing="{Binding IsRefreshing, Mode=TwoWay}" Command="{Binding RefreshCommand}">
<ScrollView>
<dd:CanvasView x:Name="EconomicIndicatorsCanvas" Renderer="{Binding Renderer}"/>
</ScrollView>
</RefreshView>
</Grid>
</Frame>
</Grid>
</ContentPage.Content>
</ContentPage>

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Navigator.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class EconomicIndicatorsPage : ContentPage
{
public EconomicIndicatorsPage()
{
InitializeComponent();
}
}
}