diff --git a/OpenHAB.Windows/App.xaml b/OpenHAB.Windows/App.xaml
index ab7ef1ea..f23e9584 100644
--- a/OpenHAB.Windows/App.xaml
+++ b/OpenHAB.Windows/App.xaml
@@ -18,10 +18,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -34,9 +46,22 @@
+
+
+
+
+
+
+
+
diff --git a/OpenHAB.Windows/App.xaml.cs b/OpenHAB.Windows/App.xaml.cs
index c6e64fe0..07fc6960 100644
--- a/OpenHAB.Windows/App.xaml.cs
+++ b/OpenHAB.Windows/App.xaml.cs
@@ -2,6 +2,10 @@
using OpenHAB.Windows.View;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
+using Windows.Foundation.Metadata;
+using Windows.UI;
+using Windows.UI.Core;
+using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
@@ -29,8 +33,19 @@ public App()
/// will be used such as when the application is launched to open a specific file.
///
/// Details about the launch request and process.
- protected override void OnLaunched(LaunchActivatedEventArgs e)
+ protected override async void OnLaunched(LaunchActivatedEventArgs e)
{
+ if (ApiInformation.IsTypePresent("Windows.UI.ViewManagement.StatusBar"))
+ {
+ var statusbar = StatusBar.GetForCurrentView();
+ await statusbar.ShowAsync();
+ statusbar.BackgroundColor = Color.FromArgb(255, 34, 40, 40);
+ statusbar.BackgroundOpacity = 1;
+ statusbar.ForegroundColor = Colors.White;
+ }
+
+ SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested;
+
var rootFrame = Window.Current.Content as Frame;
// Do not repeat app initialization when the Window already has content,
@@ -66,6 +81,11 @@ protected override void OnLaunched(LaunchActivatedEventArgs e)
}
}
+ private void OnBackRequested(object sender, BackRequestedEventArgs e)
+ {
+ e.Handled = true;
+ }
+
///
/// Invoked when Navigation to a certain page fails
///
diff --git a/OpenHAB.Windows/Assets/LogoFlat.png b/OpenHAB.Windows/Assets/LogoFlat.png
new file mode 100644
index 00000000..ad8f294e
Binary files /dev/null and b/OpenHAB.Windows/Assets/LogoFlat.png differ
diff --git a/OpenHAB.Windows/Assets/LogoSplash.jpg b/OpenHAB.Windows/Assets/LogoSplash.jpg
new file mode 100644
index 00000000..0a0c384b
Binary files /dev/null and b/OpenHAB.Windows/Assets/LogoSplash.jpg differ
diff --git a/OpenHAB.Windows/Assets/NewStoreLogo.scale-100.png b/OpenHAB.Windows/Assets/NewStoreLogo.scale-100.png
new file mode 100644
index 00000000..866d151f
Binary files /dev/null and b/OpenHAB.Windows/Assets/NewStoreLogo.scale-100.png differ
diff --git a/OpenHAB.Windows/Assets/NewStoreLogo.scale-125.png b/OpenHAB.Windows/Assets/NewStoreLogo.scale-125.png
new file mode 100644
index 00000000..f9109832
Binary files /dev/null and b/OpenHAB.Windows/Assets/NewStoreLogo.scale-125.png differ
diff --git a/OpenHAB.Windows/Assets/NewStoreLogo.scale-150.png b/OpenHAB.Windows/Assets/NewStoreLogo.scale-150.png
new file mode 100644
index 00000000..c07566cb
Binary files /dev/null and b/OpenHAB.Windows/Assets/NewStoreLogo.scale-150.png differ
diff --git a/OpenHAB.Windows/Assets/NewStoreLogo.scale-200.png b/OpenHAB.Windows/Assets/NewStoreLogo.scale-200.png
new file mode 100644
index 00000000..714349bc
Binary files /dev/null and b/OpenHAB.Windows/Assets/NewStoreLogo.scale-200.png differ
diff --git a/OpenHAB.Windows/Assets/NewStoreLogo.scale-400.png b/OpenHAB.Windows/Assets/NewStoreLogo.scale-400.png
new file mode 100644
index 00000000..9d3c3a91
Binary files /dev/null and b/OpenHAB.Windows/Assets/NewStoreLogo.scale-400.png differ
diff --git a/OpenHAB.Windows/Assets/SplashScreen.scale-100.png b/OpenHAB.Windows/Assets/SplashScreen.scale-100.png
new file mode 100644
index 00000000..0716d66b
Binary files /dev/null and b/OpenHAB.Windows/Assets/SplashScreen.scale-100.png differ
diff --git a/OpenHAB.Windows/Assets/SplashScreen.scale-125.png b/OpenHAB.Windows/Assets/SplashScreen.scale-125.png
new file mode 100644
index 00000000..7e2897e6
Binary files /dev/null and b/OpenHAB.Windows/Assets/SplashScreen.scale-125.png differ
diff --git a/OpenHAB.Windows/Assets/SplashScreen.scale-150.png b/OpenHAB.Windows/Assets/SplashScreen.scale-150.png
new file mode 100644
index 00000000..5008112d
Binary files /dev/null and b/OpenHAB.Windows/Assets/SplashScreen.scale-150.png differ
diff --git a/OpenHAB.Windows/Assets/SplashScreen.scale-200.png b/OpenHAB.Windows/Assets/SplashScreen.scale-200.png
index 023e7f1f..35bdfc99 100644
Binary files a/OpenHAB.Windows/Assets/SplashScreen.scale-200.png and b/OpenHAB.Windows/Assets/SplashScreen.scale-200.png differ
diff --git a/OpenHAB.Windows/Assets/SplashScreen.scale-400.png b/OpenHAB.Windows/Assets/SplashScreen.scale-400.png
new file mode 100644
index 00000000..9e3ffa0a
Binary files /dev/null and b/OpenHAB.Windows/Assets/SplashScreen.scale-400.png differ
diff --git a/OpenHAB.Windows/Assets/Square150x150Logo.scale-100.png b/OpenHAB.Windows/Assets/Square150x150Logo.scale-100.png
new file mode 100644
index 00000000..2c40f8e4
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square150x150Logo.scale-100.png differ
diff --git a/OpenHAB.Windows/Assets/Square150x150Logo.scale-125.png b/OpenHAB.Windows/Assets/Square150x150Logo.scale-125.png
new file mode 100644
index 00000000..55e8b5c0
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square150x150Logo.scale-125.png differ
diff --git a/OpenHAB.Windows/Assets/Square150x150Logo.scale-150.png b/OpenHAB.Windows/Assets/Square150x150Logo.scale-150.png
new file mode 100644
index 00000000..7f6137ec
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square150x150Logo.scale-150.png differ
diff --git a/OpenHAB.Windows/Assets/Square150x150Logo.scale-200.png b/OpenHAB.Windows/Assets/Square150x150Logo.scale-200.png
index af49fec1..9c24d6bd 100644
Binary files a/OpenHAB.Windows/Assets/Square150x150Logo.scale-200.png and b/OpenHAB.Windows/Assets/Square150x150Logo.scale-200.png differ
diff --git a/OpenHAB.Windows/Assets/Square150x150Logo.scale-400.png b/OpenHAB.Windows/Assets/Square150x150Logo.scale-400.png
new file mode 100644
index 00000000..0b5e55d8
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square150x150Logo.scale-400.png differ
diff --git a/OpenHAB.Windows/Assets/Square310x310Logo.scale-100.png b/OpenHAB.Windows/Assets/Square310x310Logo.scale-100.png
new file mode 100644
index 00000000..f9e8528c
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square310x310Logo.scale-100.png differ
diff --git a/OpenHAB.Windows/Assets/Square310x310Logo.scale-125.png b/OpenHAB.Windows/Assets/Square310x310Logo.scale-125.png
new file mode 100644
index 00000000..a954f7fa
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square310x310Logo.scale-125.png differ
diff --git a/OpenHAB.Windows/Assets/Square310x310Logo.scale-150.png b/OpenHAB.Windows/Assets/Square310x310Logo.scale-150.png
new file mode 100644
index 00000000..69e7bbfb
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square310x310Logo.scale-150.png differ
diff --git a/OpenHAB.Windows/Assets/Square310x310Logo.scale-200.png b/OpenHAB.Windows/Assets/Square310x310Logo.scale-200.png
new file mode 100644
index 00000000..6a8bd4d4
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square310x310Logo.scale-200.png differ
diff --git a/OpenHAB.Windows/Assets/Square310x310Logo.scale-400.png b/OpenHAB.Windows/Assets/Square310x310Logo.scale-400.png
new file mode 100644
index 00000000..3187e544
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square310x310Logo.scale-400.png differ
diff --git a/OpenHAB.Windows/Assets/Square44x44Logo.scale-100.png b/OpenHAB.Windows/Assets/Square44x44Logo.scale-100.png
new file mode 100644
index 00000000..9ffb5b19
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square44x44Logo.scale-100.png differ
diff --git a/OpenHAB.Windows/Assets/Square44x44Logo.scale-125.png b/OpenHAB.Windows/Assets/Square44x44Logo.scale-125.png
new file mode 100644
index 00000000..5a750c66
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square44x44Logo.scale-125.png differ
diff --git a/OpenHAB.Windows/Assets/Square44x44Logo.scale-150.png b/OpenHAB.Windows/Assets/Square44x44Logo.scale-150.png
new file mode 100644
index 00000000..89054e71
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square44x44Logo.scale-150.png differ
diff --git a/OpenHAB.Windows/Assets/Square44x44Logo.scale-200.png b/OpenHAB.Windows/Assets/Square44x44Logo.scale-200.png
index ce342a2e..19772d81 100644
Binary files a/OpenHAB.Windows/Assets/Square44x44Logo.scale-200.png and b/OpenHAB.Windows/Assets/Square44x44Logo.scale-200.png differ
diff --git a/OpenHAB.Windows/Assets/Square44x44Logo.scale-400.png b/OpenHAB.Windows/Assets/Square44x44Logo.scale-400.png
new file mode 100644
index 00000000..fdbf9e92
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square44x44Logo.scale-400.png differ
diff --git a/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-16.png b/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-16.png
new file mode 100644
index 00000000..90ae8ed4
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-16.png differ
diff --git a/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-16_altform-unplated.png b/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-16_altform-unplated.png
new file mode 100644
index 00000000..02675500
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-16_altform-unplated.png differ
diff --git a/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-24.png b/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-24.png
new file mode 100644
index 00000000..1f74c059
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-24.png differ
diff --git a/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
index f6c02ce9..51cfcf78 100644
Binary files a/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-24_altform-unplated.png and b/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-24_altform-unplated.png differ
diff --git a/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-256.png b/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-256.png
new file mode 100644
index 00000000..7f04b407
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-256.png differ
diff --git a/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-256_altform-unplated.png b/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-256_altform-unplated.png
new file mode 100644
index 00000000..ddf8a348
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-256_altform-unplated.png differ
diff --git a/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-32.png b/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-32.png
new file mode 100644
index 00000000..295b8466
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-32.png differ
diff --git a/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-32_altform-unplated.png b/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-32_altform-unplated.png
new file mode 100644
index 00000000..ca4280f2
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-32_altform-unplated.png differ
diff --git a/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-48.png b/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-48.png
new file mode 100644
index 00000000..f76efaa2
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-48.png differ
diff --git a/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-48_altform-unplated.png b/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-48_altform-unplated.png
new file mode 100644
index 00000000..190a6970
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square44x44Logo.targetsize-48_altform-unplated.png differ
diff --git a/OpenHAB.Windows/Assets/Square71x71Logo.scale-100.png b/OpenHAB.Windows/Assets/Square71x71Logo.scale-100.png
new file mode 100644
index 00000000..28dbb0b8
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square71x71Logo.scale-100.png differ
diff --git a/OpenHAB.Windows/Assets/Square71x71Logo.scale-125.png b/OpenHAB.Windows/Assets/Square71x71Logo.scale-125.png
new file mode 100644
index 00000000..13280dde
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square71x71Logo.scale-125.png differ
diff --git a/OpenHAB.Windows/Assets/Square71x71Logo.scale-150.png b/OpenHAB.Windows/Assets/Square71x71Logo.scale-150.png
new file mode 100644
index 00000000..9bc9ef97
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square71x71Logo.scale-150.png differ
diff --git a/OpenHAB.Windows/Assets/Square71x71Logo.scale-200.png b/OpenHAB.Windows/Assets/Square71x71Logo.scale-200.png
new file mode 100644
index 00000000..7631da66
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square71x71Logo.scale-200.png differ
diff --git a/OpenHAB.Windows/Assets/Square71x71Logo.scale-400.png b/OpenHAB.Windows/Assets/Square71x71Logo.scale-400.png
new file mode 100644
index 00000000..26a63f73
Binary files /dev/null and b/OpenHAB.Windows/Assets/Square71x71Logo.scale-400.png differ
diff --git a/OpenHAB.Windows/Assets/Wide310x150Logo.scale-100.png b/OpenHAB.Windows/Assets/Wide310x150Logo.scale-100.png
new file mode 100644
index 00000000..06b4828e
Binary files /dev/null and b/OpenHAB.Windows/Assets/Wide310x150Logo.scale-100.png differ
diff --git a/OpenHAB.Windows/Assets/Wide310x150Logo.scale-125.png b/OpenHAB.Windows/Assets/Wide310x150Logo.scale-125.png
new file mode 100644
index 00000000..393fa927
Binary files /dev/null and b/OpenHAB.Windows/Assets/Wide310x150Logo.scale-125.png differ
diff --git a/OpenHAB.Windows/Assets/Wide310x150Logo.scale-150.png b/OpenHAB.Windows/Assets/Wide310x150Logo.scale-150.png
new file mode 100644
index 00000000..891c4770
Binary files /dev/null and b/OpenHAB.Windows/Assets/Wide310x150Logo.scale-150.png differ
diff --git a/OpenHAB.Windows/Assets/Wide310x150Logo.scale-200.png b/OpenHAB.Windows/Assets/Wide310x150Logo.scale-200.png
index 288995b3..8c4a23db 100644
Binary files a/OpenHAB.Windows/Assets/Wide310x150Logo.scale-200.png and b/OpenHAB.Windows/Assets/Wide310x150Logo.scale-200.png differ
diff --git a/OpenHAB.Windows/Assets/Wide310x150Logo.scale-400.png b/OpenHAB.Windows/Assets/Wide310x150Logo.scale-400.png
new file mode 100644
index 00000000..68b83685
Binary files /dev/null and b/OpenHAB.Windows/Assets/Wide310x150Logo.scale-400.png differ
diff --git a/OpenHAB.Windows/Assets/background.jpg b/OpenHAB.Windows/Assets/background.jpg
new file mode 100644
index 00000000..f7a2c403
Binary files /dev/null and b/OpenHAB.Windows/Assets/background.jpg differ
diff --git a/OpenHAB.Windows/Assets/openhab-logo-square.png b/OpenHAB.Windows/Assets/openhab-logo-square.png
new file mode 100644
index 00000000..ca2587e8
Binary files /dev/null and b/OpenHAB.Windows/Assets/openhab-logo-square.png differ
diff --git a/OpenHAB.Windows/Controls/ChartWidget.xaml b/OpenHAB.Windows/Controls/ChartWidget.xaml
new file mode 100644
index 00000000..568d09ef
--- /dev/null
+++ b/OpenHAB.Windows/Controls/ChartWidget.xaml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/OpenHAB.Windows/Controls/ChartWidget.xaml.cs b/OpenHAB.Windows/Controls/ChartWidget.xaml.cs
new file mode 100644
index 00000000..79ad750b
--- /dev/null
+++ b/OpenHAB.Windows/Controls/ChartWidget.xaml.cs
@@ -0,0 +1,50 @@
+using System;
+using System.ComponentModel;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Media.Imaging;
+using Microsoft.Practices.ServiceLocation;
+using OpenHAB.Core.Common;
+using OpenHAB.Core.Contracts.Services;
+
+namespace OpenHAB.Windows.Controls
+{
+ ///
+ /// Widget control that represents an OpenHAB slider
+ ///
+ public sealed partial class ChartWidget : WidgetBase
+ {
+ public static readonly DependencyProperty ChartUriProperty = DependencyProperty.Register(
+ "ChartUri", typeof(string), typeof(ChartWidget), new PropertyMetadata(default(string)));
+
+ public string ChartUri
+ {
+ get { return (string) GetValue(ChartUriProperty); }
+ set { SetValue(ChartUriProperty, value); }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ChartWidget()
+ {
+ InitializeComponent();
+ Loaded += OnLoaded;
+ }
+
+ private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
+ {
+ var settingsService = ServiceLocator.Current.GetInstance();
+ var settings = settingsService.Load();
+ var serverUrl = settings.IsRunningInDemoMode.Value ? Constants.Api.DemoModeUrl : settings.OpenHABUrl;
+
+ if (!serverUrl.EndsWith("/"))
+ {
+ serverUrl += "/";
+ }
+
+ // http://demo.openhab.org:8080/chart?groups=Weather_Chart&period=d
+ ChartUri = $"{serverUrl}chart?groups={Widget.Item.Name}&period=d";
+ Chart.Source = new BitmapImage(new Uri(ChartUri));
+ }
+ }
+}
diff --git a/OpenHAB.Windows/Controls/ColorMap.xaml b/OpenHAB.Windows/Controls/ColorMap.xaml
new file mode 100644
index 00000000..b9b2a424
--- /dev/null
+++ b/OpenHAB.Windows/Controls/ColorMap.xaml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/OpenHAB.Windows/Controls/ColorMap.xaml.cs b/OpenHAB.Windows/Controls/ColorMap.xaml.cs
new file mode 100644
index 00000000..ed6a8de6
--- /dev/null
+++ b/OpenHAB.Windows/Controls/ColorMap.xaml.cs
@@ -0,0 +1,246 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Numerics;
+using System.Runtime.InteropServices.WindowsRuntime;
+using System.Threading.Tasks;
+using OpenHAB.Core.Common;
+using Windows.Foundation;
+using Windows.UI;
+using Windows.UI.Input;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Input;
+using Windows.UI.Xaml.Media;
+using Windows.UI.Xaml.Media.Imaging;
+using ColorHelper = OpenHAB.Core.Common.ColorHelper;
+
+namespace OpenHAB.Windows.Controls
+{
+ ///
+ /// Colorpicker control
+ ///
+ public sealed partial class ColorMap : UserControl
+ {
+ private readonly GradientStop _lightnessStart;
+ private readonly GradientStop _lightnessMid;
+ private readonly GradientStop _lightnessEnd;
+
+ private PointerPoint _lastPoint;
+ private WriteableBitmap _bitmap;
+ private double _colorX;
+ private double _colorY;
+ private bool _settingColor;
+ private bool _isloaded;
+
+ ///
+ /// Event that fires whenever a new color is selected
+ ///
+ public event EventHandler ColorChanged;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ColorMap()
+ {
+ InitializeComponent();
+
+ Loaded += MeshCanvas_Loaded;
+
+ ellipse.PointerMoved += Image3_PointerMoved;
+ ellipse.PointerPressed += Image3_PointerPressed;
+ ellipse.PointerReleased += Image3_PointerReleased;
+
+ var lightnessGradient = new LinearGradientBrush
+ {
+ StartPoint = new Point(0, 0),
+ EndPoint = new Point(0, 1)
+ };
+
+ _lightnessStart = new GradientStop();
+ _lightnessMid = new GradientStop { Offset = 0.5 };
+ _lightnessEnd = new GradientStop { Offset = 1 };
+ lightnessGradient.GradientStops = new GradientStopCollection()
+ {
+ _lightnessStart, _lightnessMid, _lightnessEnd,
+ };
+ }
+
+ ///
+ /// Gets or sets the Color property
+ ///
+ public Color Color
+ {
+ get { return (Color)GetValue(ColorProperty); }
+ set { SetValue(ColorProperty, value); }
+ }
+
+ ///
+ /// Bindable property for the Color property
+ ///
+ public static readonly DependencyProperty ColorProperty =
+ DependencyProperty.Register("Color", typeof(Color), typeof(ColorMap), new PropertyMetadata(default(Color), OnColorChanged));
+
+ private static void OnColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var map = d as ColorMap;
+ map?.ColorChanged?.Invoke(map, new ColorChangedEventArgs((Color)e.NewValue));
+
+ if (map == null || map._settingColor)
+ {
+ return;
+ }
+
+ var col = (Color)e.NewValue;
+ var hsl = ColorHelper.ToHSL(col);
+
+ map._lightnessMid.Color = ColorHelper.FromHSL(new Vector4(hsl.X, 1, 0.5f, 1));
+
+ double angle = Math.PI * 2 * hsl.X;
+ Vector2 normalized = new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle));
+ Vector2 halfSize = new Vector2(
+ (float)map.ellipse.ActualWidth / 2,
+ (float)map.ellipse.ActualHeight / 2);
+
+ Vector2 pos = ((hsl.Y / 2) * normalized * halfSize * new Vector2(1, -1)) + halfSize;
+
+ map._colorX = pos.X;
+ map._colorY = pos.Y;
+ map.UpdateThumb();
+ }
+
+ private void Image3_PointerPressed(object sender, PointerRoutedEventArgs e)
+ {
+ ellipse.CapturePointer(e.Pointer);
+ _lastPoint = e.GetCurrentPoint(ellipse);
+ _colorX = _lastPoint.Position.X;
+ _colorY = _lastPoint.Position.Y;
+ UpdateColor();
+ UpdateThumb();
+ e.Handled = true;
+ }
+
+ private void Image3_PointerReleased(object sender, PointerRoutedEventArgs e)
+ {
+ ellipse.ReleasePointerCapture(e.Pointer);
+ _lastPoint = null;
+ e.Handled = true;
+ }
+
+ private void Image3_PointerMoved(object sender, PointerRoutedEventArgs e)
+ {
+ if (ellipse.PointerCaptures?.Any(p => p.PointerId == e.Pointer.PointerId) != true)
+ {
+ return;
+ }
+
+ _lastPoint = e.GetCurrentPoint(ellipse);
+ _colorX = _lastPoint.Position.X;
+ _colorY = _lastPoint.Position.Y;
+
+ var bounds = new Rect(0, 0, ellipse.ActualWidth, ellipse.ActualHeight);
+ if (!bounds.Contains(_lastPoint.Position) || !UpdateColor())
+ {
+ return;
+ }
+
+ UpdateThumb();
+ e.Handled = true;
+ }
+
+ private void UpdateThumb()
+ {
+ Canvas.SetLeft(thumb, _colorX - (thumb.ActualWidth / 2));
+ Canvas.SetTop(thumb, _colorY - (thumb.ActualHeight / 2));
+ thumb.Visibility = Visibility.Visible;
+ }
+
+ private bool UpdateColor()
+ {
+ if (!_isloaded)
+ {
+ return false;
+ }
+
+ var x = _colorX / ellipse.ActualWidth;
+ var y = 1 - (_colorY / ellipse.ActualHeight);
+ var selectedColor = CalcWheelColor((float)x, 1 - (float)y, 100);
+
+ if (selectedColor.A <= 0)
+ {
+ return false;
+ }
+
+ SetColor(selectedColor);
+ _lightnessStart.Color = Colors.White;
+ _lightnessMid.Color = CalcWheelColor((float)x, 1 - (float)y, 0.5f);
+ _lightnessEnd.Color = Colors.Black;
+ return true;
+ }
+
+ private void SetColor(Color color)
+ {
+ _settingColor = true;
+ Color = color;
+ _settingColor = false;
+ }
+
+ private async void MeshCanvas_Loaded(object sender, RoutedEventArgs e)
+ {
+ _bitmap = new WriteableBitmap(1000, 1000);
+ await CreateHueCircle(0.5f);
+ image3.ImageSource = _bitmap;
+ _isloaded = true;
+ }
+
+ private Task CreateHueCircle(float lightness)
+ {
+ return FillBitmap(_bitmap, (x, y) => CalcWheelColor(x, y, lightness));
+ }
+
+ private Color CalcWheelColor(float x, float y, float lightness)
+ {
+ x = x - 0.5f;
+ y = (1 - y) - 0.5f;
+ float saturation = 2 * (float)Math.Sqrt((x * x) + (y * y));
+ float hue = y < 0 ?
+ (float)Math.Atan2(-y, -x) + (float)Math.PI :
+ (float)Math.Atan2(y, x);
+
+ if (saturation > 1)
+ {
+ saturation = 1;
+ }
+
+ return ColorHelper.FromHSL(new Vector4(hue / ((float)Math.PI * 2), saturation, lightness, 1));
+ }
+
+ private async Task FillBitmap(WriteableBitmap bmp, Func fillPixel)
+ {
+ var stream = bmp.PixelBuffer.AsStream();
+ int width = bmp.PixelWidth;
+ int height = bmp.PixelHeight;
+ await Task.Run(() =>
+ {
+ for (int y = 0; y < width; y++)
+ {
+ for (int x = 0; x < height; x++)
+ {
+ var color = fillPixel((float)x / width, (float)y / height);
+ WriteBgra(stream, color);
+ }
+ }
+ });
+ stream.Dispose();
+ bmp.Invalidate();
+ }
+
+ private void WriteBgra(Stream stream, Color color)
+ {
+ stream.WriteByte(color.B);
+ stream.WriteByte(color.G);
+ stream.WriteByte(color.R);
+ stream.WriteByte(color.A);
+ }
+ }
+}
diff --git a/OpenHAB.Windows/Controls/ColorWidget.xaml b/OpenHAB.Windows/Controls/ColorWidget.xaml
new file mode 100644
index 00000000..e92b5571
--- /dev/null
+++ b/OpenHAB.Windows/Controls/ColorWidget.xaml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/OpenHAB.Windows/Controls/ColorWidget.xaml.cs b/OpenHAB.Windows/Controls/ColorWidget.xaml.cs
new file mode 100644
index 00000000..07b78ba0
--- /dev/null
+++ b/OpenHAB.Windows/Controls/ColorWidget.xaml.cs
@@ -0,0 +1,72 @@
+using System;
+using GalaSoft.MvvmLight.Messaging;
+using OpenHAB.Core.Common;
+using OpenHAB.Core.Messages;
+using Windows.UI;
+using Windows.UI.Xaml;
+
+namespace OpenHAB.Windows.Controls
+{
+ ///
+ /// Widget control that represents an OpenHAB text
+ ///
+ public sealed partial class ColorWidget : WidgetBase
+ {
+ private Color _selectedColor;
+
+ ///
+ /// Gets or sets the color currently selected in the colorpicker widget
+ ///
+ public Color SelectedColor
+ {
+ get
+ {
+ return _selectedColor;
+ }
+
+ set
+ {
+ if (_selectedColor == value)
+ {
+ return;
+ }
+
+ _selectedColor = value;
+ RaisePropertyChanged();
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ColorWidget()
+ {
+ InitializeComponent();
+ Loaded += OnLoaded;
+ }
+
+ private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
+ {
+ var rgbString = Widget.Item.State.Split(',');
+
+ if (rgbString.Length == 0)
+ {
+ return;
+ }
+
+ SelectedColor = Core.Common.ColorHelper.FromHSV(Convert.ToDouble(rgbString[0]), Convert.ToDouble(rgbString[1]), Convert.ToDouble(rgbString[2]));
+ }
+
+ private void ColorMap_OnColorChanged(object sender, ColorChangedEventArgs e)
+ {
+ if (Widget == null)
+ {
+ return;
+ }
+
+ var colorMap = (ColorMap)sender;
+ var hsv = Core.Common.ColorHelper.ToHSV(colorMap.Color);
+ Messenger.Default.Send(new TriggerCommandMessage(Widget.Item, $"{hsv.X},{hsv.Y},{hsv.Z}"));
+ }
+ }
+}
diff --git a/OpenHAB.Windows/Controls/FrameWidget.xaml b/OpenHAB.Windows/Controls/FrameWidget.xaml
index c60fcee0..a21f2bae 100644
--- a/OpenHAB.Windows/Controls/FrameWidget.xaml
+++ b/OpenHAB.Windows/Controls/FrameWidget.xaml
@@ -1,21 +1,64 @@
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/OpenHAB.Windows/Controls/FrameWidget.xaml.cs b/OpenHAB.Windows/Controls/FrameWidget.xaml.cs
index 3808956a..1098e899 100644
--- a/OpenHAB.Windows/Controls/FrameWidget.xaml.cs
+++ b/OpenHAB.Windows/Controls/FrameWidget.xaml.cs
@@ -1,4 +1,9 @@
-namespace OpenHAB.Windows.Controls
+using GalaSoft.MvvmLight.Messaging;
+using OpenHAB.Core.Messages;
+using OpenHAB.Core.Model;
+using Windows.UI.Xaml.Controls;
+
+namespace OpenHAB.Windows.Controls
{
///
/// Widget control that represents an OpenHAB frame
@@ -12,5 +17,10 @@ public FrameWidget()
{
InitializeComponent();
}
+
+ private void OnItemClick(object sender, ItemClickEventArgs e)
+ {
+ Messenger.Default.Send(new WidgetClickedMessage(e.ClickedItem as OpenHABWidget));
+ }
}
}
diff --git a/OpenHAB.Windows/Controls/ImageLabel.xaml b/OpenHAB.Windows/Controls/ImageLabel.xaml
index 70cc309e..3fa878ea 100644
--- a/OpenHAB.Windows/Controls/ImageLabel.xaml
+++ b/OpenHAB.Windows/Controls/ImageLabel.xaml
@@ -2,22 +2,20 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:local="using:OpenHAB.Windows.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="300"
d:DesignWidth="400"
mc:Ignorable="d">
-
-
-
+
+
diff --git a/OpenHAB.Windows/Controls/ImageLabel.xaml.cs b/OpenHAB.Windows/Controls/ImageLabel.xaml.cs
index e91e3f35..5e7c697a 100644
--- a/OpenHAB.Windows/Controls/ImageLabel.xaml.cs
+++ b/OpenHAB.Windows/Controls/ImageLabel.xaml.cs
@@ -34,7 +34,7 @@ private static void IconChangedCallback(DependencyObject dependencyObject, Depen
public string IconPath
{
get { return (string)GetValue(IconPathProperty); }
- set { SetValue(IconPathProperty, value); }
+ set { SetValue(IconPathProperty, value ?? string.Empty); }
}
///
@@ -49,7 +49,7 @@ public string IconPath
public string LabelText
{
get { return (string)GetValue(TextProperty); }
- set { SetValue(TextProperty, value); }
+ set { SetValue(TextProperty, value ?? string.Empty); }
}
private static void TextChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
diff --git a/OpenHAB.Windows/Controls/ImageWidget.xaml b/OpenHAB.Windows/Controls/ImageWidget.xaml
index a3b6fd27..f1435ed6 100644
--- a/OpenHAB.Windows/Controls/ImageWidget.xaml
+++ b/OpenHAB.Windows/Controls/ImageWidget.xaml
@@ -8,25 +8,37 @@
d:DesignWidth="400"
mc:Ignorable="d">
-
-
-
+
+
+
+
+
-
+ PrimaryButtonText="Close">
+
+
diff --git a/OpenHAB.Windows/Controls/MjpegWidget.xaml b/OpenHAB.Windows/Controls/MjpegWidget.xaml
new file mode 100644
index 00000000..67c8bbe1
--- /dev/null
+++ b/OpenHAB.Windows/Controls/MjpegWidget.xaml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/OpenHAB.Windows/Controls/MjpegWidget.xaml.cs b/OpenHAB.Windows/Controls/MjpegWidget.xaml.cs
new file mode 100644
index 00000000..d165b8a0
--- /dev/null
+++ b/OpenHAB.Windows/Controls/MjpegWidget.xaml.cs
@@ -0,0 +1,93 @@
+using System;
+using MJPEGDecoderWinRTLib;
+using Windows.Storage.Streams;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Input;
+using Windows.UI.Xaml.Media.Imaging;
+
+namespace OpenHAB.Windows.Controls
+{
+ ///
+ /// Widget control that represents an OpenHAB Image
+ ///
+ public sealed partial class MjpegWidget : WidgetBase
+ {
+ private BitmapImage _cameraBitmapImage;
+ private MJPEGDecoder _mjpegDecoder;
+
+ ///
+ /// Gets or sets the camera bitmapimage
+ ///
+ public BitmapImage CameraBitmapImage
+ {
+ get
+ {
+ return _cameraBitmapImage;
+ }
+
+ set
+ {
+ if (_cameraBitmapImage == value)
+ {
+ return;
+ }
+
+ _cameraBitmapImage = value;
+ RaisePropertyChanged();
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public MjpegWidget()
+ {
+ InitializeComponent();
+ Loaded += OnLoaded;
+ }
+
+ private async void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
+ {
+ _mjpegDecoder = new MJPEGDecoder();
+ CameraBitmapImage = new BitmapImage();
+
+ // Register listener methods
+ _mjpegDecoder.FrameReady += MjpegDecoder_FrameReady;
+ _mjpegDecoder.Error += MjpegDecoder_Error;
+
+ // Construct Http Uri
+ string requestUri = Widget?.Url;
+
+ // Tell MJPEGDecoder to connect to the IP camera, parse the mjpeg stream, and
+ // report the received image frames.
+ await _mjpegDecoder.ParseStreamAsync(requestUri, string.Empty, string.Empty);
+ }
+
+ private async void MjpegDecoder_FrameReady(object sender, FrameReadyEventArgs e)
+ {
+ // Copy the received FrameBuffer to an InMemoryRandomAccessStream.
+ using (InMemoryRandomAccessStream ms = new InMemoryRandomAccessStream())
+ {
+ using (DataWriter writer = new DataWriter(ms.GetOutputStreamAt(0)))
+ {
+ writer.WriteBytes(e.FrameBuffer);
+ await writer.StoreAsync();
+ }
+
+ // Update source of CameraBitmap with the memory stream
+ CameraBitmapImage.SetSource(ms);
+ }
+ }
+
+ private void MjpegDecoder_Error(object sender, ErrorEventArgs e)
+ {
+ // ErrorMsg = e.Message;
+ }
+
+ private async void ImageWidget_OnTapped(object sender, TappedRoutedEventArgs e)
+ {
+ CameraViewDialog.MinWidth = CameraBitmapImage.PixelWidth;
+ await CameraViewDialog.ShowAsync();
+ }
+ }
+}
diff --git a/OpenHAB.Windows/Controls/PageLinkWidget.xaml b/OpenHAB.Windows/Controls/PageLinkWidget.xaml
new file mode 100644
index 00000000..d6f45d76
--- /dev/null
+++ b/OpenHAB.Windows/Controls/PageLinkWidget.xaml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/OpenHAB.Windows/Controls/PageLinkWidget.xaml.cs b/OpenHAB.Windows/Controls/PageLinkWidget.xaml.cs
new file mode 100644
index 00000000..ab9bc521
--- /dev/null
+++ b/OpenHAB.Windows/Controls/PageLinkWidget.xaml.cs
@@ -0,0 +1,22 @@
+using GalaSoft.MvvmLight.Messaging;
+using OpenHAB.Core.Messages;
+using OpenHAB.Core.Model;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+
+namespace OpenHAB.Windows.Controls
+{
+ ///
+ /// Widget control that represents an OpenHAB switch
+ ///
+ public sealed partial class PageLinkWidget : WidgetBase
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public PageLinkWidget()
+ {
+ InitializeComponent();
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenHAB.Windows/Controls/RadialSlider.cs b/OpenHAB.Windows/Controls/RadialSlider.cs
new file mode 100644
index 00000000..d4a1711d
--- /dev/null
+++ b/OpenHAB.Windows/Controls/RadialSlider.cs
@@ -0,0 +1,559 @@
+using System;
+using Windows.Foundation;
+using Windows.UI;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Input;
+using Windows.UI.Xaml.Media;
+using Windows.UI.Xaml.Shapes;
+
+namespace OpenHAB.Windows.Controls
+{
+ ///
+ /// A Percentage Ring Control.
+ ///
+ //// All calculations are for a 200x200 square. The ViewBox control will do the rest.
+ [TemplatePart(Name = ContainerPartName, Type = typeof(Grid))]
+ [TemplatePart(Name = ScalePartName, Type = typeof(Path))]
+ [TemplatePart(Name = TrailPartName, Type = typeof(Path))]
+ [TemplatePart(Name = ValueTextPartName, Type = typeof(TextBlock))]
+ public class RadialSlider : Control
+ {
+ ///
+ /// Triggers whenever the slider changes
+ ///
+ public event EventHandler ValueChanged;
+
+ ///
+ /// Identifies the optional StepSize property.
+ ///
+ public static readonly DependencyProperty StepSizeProperty =
+ DependencyProperty.Register(nameof(StepSize), typeof(double), typeof(RadialSlider), new PropertyMetadata(0.0));
+
+ ///
+ /// Identifies the IsInteractive dependency property.
+ ///
+ public static readonly DependencyProperty IsInteractiveProperty =
+ DependencyProperty.Register(nameof(IsInteractive), typeof(bool), typeof(RadialSlider), new PropertyMetadata(false, OnInteractivityChanged));
+
+ ///
+ /// Identifies the ScaleWidth dependency property.
+ ///
+ public static readonly DependencyProperty ScaleWidthProperty =
+ DependencyProperty.Register(nameof(ScaleWidth), typeof(double), typeof(RadialSlider), new PropertyMetadata(25.0, OnScaleChanged));
+
+ ///
+ /// Identifies the Value dependency property.
+ ///
+ public static readonly DependencyProperty ValueProperty =
+ DependencyProperty.Register(nameof(Value), typeof(double), typeof(RadialSlider), new PropertyMetadata(0.0, OnValueChanged));
+
+ ///
+ /// Identifies the TrailBrush dependency property.
+ ///
+ public static readonly DependencyProperty TrailBrushProperty =
+ DependencyProperty.Register(nameof(TrailBrush), typeof(Brush), typeof(RadialSlider), new PropertyMetadata(new SolidColorBrush(Colors.Orange), OnValueChanged));
+
+ ///
+ /// Identifies the TrailStartCap dependency property.
+ ///
+ public static readonly DependencyProperty TrailStartCapProperty =
+ DependencyProperty.Register(nameof(TrailStartCap), typeof(PenLineCap), typeof(RadialSlider), new PropertyMetadata(PenLineCap.Round, OnValueChanged));
+
+ ///
+ /// Identifies the TrailEndCap dependency property.
+ ///
+ public static readonly DependencyProperty TrailEndCapProperty =
+ DependencyProperty.Register(nameof(TrailEndCap), typeof(PenLineCap), typeof(RadialSlider), new PropertyMetadata(PenLineCap.Triangle, OnValueChanged));
+
+ ///
+ /// Identifies the ScaleBrush dependency property.
+ ///
+ public static readonly DependencyProperty ScaleBrushProperty =
+ DependencyProperty.Register(nameof(ScaleBrush), typeof(Brush), typeof(RadialSlider), new PropertyMetadata(new SolidColorBrush(Colors.DarkGray), OnScaleChanged));
+
+ ///
+ /// Identifies the ScaleStartCap dependency property.
+ ///
+ public static readonly DependencyProperty ScaleStartCapProperty =
+ DependencyProperty.Register(nameof(ScaleStartCap), typeof(PenLineCap), typeof(RadialSlider), new PropertyMetadata(PenLineCap.Round, OnScaleChanged));
+
+ ///
+ /// Identifies the ScaleEndCap dependency property.
+ ///
+ public static readonly DependencyProperty ScaleEndCapProperty =
+ DependencyProperty.Register(nameof(ScaleEndCap), typeof(PenLineCap), typeof(RadialSlider), new PropertyMetadata(PenLineCap.Triangle, OnScaleChanged));
+
+ ///
+ /// Identifies the ValueBrush dependency property.
+ ///
+ public static readonly DependencyProperty ValueBrushProperty =
+ DependencyProperty.Register(nameof(ValueBrush), typeof(Brush), typeof(RadialSlider), new PropertyMetadata(new SolidColorBrush(Colors.Black)));
+
+ ///
+ /// Identifies the ValueStringFormat dependency property.
+ ///
+ public static readonly DependencyProperty ValueStringFormatProperty =
+ DependencyProperty.Register(nameof(ValueStringFormat), typeof(string), typeof(RadialSlider), null);
+
+ ///
+ /// Identifies the MinAngle dependency property.
+ ///
+ public static readonly DependencyProperty MinAngleProperty =
+ DependencyProperty.Register(nameof(MinAngle), typeof(int), typeof(RadialSlider), new PropertyMetadata(0, OnScaleChanged));
+
+ ///
+ /// Identifies the MaxAngle dependency property.
+ ///
+ public static readonly DependencyProperty MaxAngleProperty =
+ DependencyProperty.Register(nameof(MaxAngle), typeof(int), typeof(RadialSlider), new PropertyMetadata(360, OnScaleChanged));
+
+ ///
+ /// Identifies the ValueAngle dependency property.
+ ///
+ protected static readonly DependencyProperty ValueAngleProperty =
+ DependencyProperty.Register(nameof(ValueAngle), typeof(double), typeof(RadialSlider), new PropertyMetadata(null));
+
+ // Template Parts.
+ private const string ContainerPartName = "PART_Container";
+ private const string ScalePartName = "PART_Scale";
+ private const string TrailPartName = "PART_Trail";
+ private const string ValueTextPartName = "PART_ValueText";
+
+ // For convenience.
+ private const double Degrees2Radians = Math.PI / 180;
+ private const double Radius = 100;
+ private const double Minimum = 0;
+ private const double Maximum = 100;
+
+ private double _normalizedMinAngle;
+ private double _normalizedMaxAngle;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public RadialSlider()
+ {
+ DefaultStyleKey = typeof(RadialSlider);
+ }
+
+ ///
+ /// Gets or sets the rounding interval for the Value.
+ ///
+ public double StepSize
+ {
+ get { return (double)GetValue(StepSizeProperty); }
+ set { SetValue(StepSizeProperty, value); }
+ }
+
+ ///
+ /// Gets or sets a value indicating whether the control accepts setting its value through interaction.
+ ///
+ public bool IsInteractive
+ {
+ get { return (bool)GetValue(IsInteractiveProperty); }
+ set { SetValue(IsInteractiveProperty, value); }
+ }
+
+ ///
+ /// Gets or sets the width of the scale, in percentage of the radius.
+ ///
+ public double ScaleWidth
+ {
+ get { return (double)GetValue(ScaleWidthProperty); }
+ set { SetValue(ScaleWidthProperty, value); }
+ }
+
+ ///
+ /// Gets or sets the current value.
+ ///
+ public double Value
+ {
+ get { return (double)GetValue(ValueProperty); }
+ set { SetValue(ValueProperty, value); }
+ }
+
+ ///
+ /// Gets or sets the trail brush.
+ ///
+ public Brush TrailBrush
+ {
+ get { return (Brush)GetValue(TrailBrushProperty); }
+ set { SetValue(TrailBrushProperty, value); }
+ }
+
+ ///
+ /// Gets or sets the StrokeStartCap for the Trail.
+ ///
+ public PenLineCap TrailStartCap
+ {
+ get { return (PenLineCap)GetValue(TrailStartCapProperty); }
+ set { SetValue(TrailStartCapProperty, value); }
+ }
+
+ ///
+ /// Gets or sets the StrokeEndCap for the Trail.
+ ///
+ public PenLineCap TrailEndCap
+ {
+ get { return (PenLineCap)GetValue(TrailEndCapProperty); }
+ set { SetValue(TrailEndCapProperty, value); }
+ }
+
+ ///
+ /// Gets or sets the scale brush.
+ ///
+ public Brush ScaleBrush
+ {
+ get { return (Brush)GetValue(ScaleBrushProperty); }
+ set { SetValue(ScaleBrushProperty, value); }
+ }
+
+ ///
+ /// Gets or sets the StrokeStartCap for the Scale.
+ ///
+ public PenLineCap ScaleStartCap
+ {
+ get { return (PenLineCap)GetValue(ScaleStartCapProperty); }
+ set { SetValue(ScaleStartCapProperty, value); }
+ }
+
+ ///
+ /// Gets or sets the StrokeEndCap for the Scale.
+ ///
+ public PenLineCap ScaleEndCap
+ {
+ get { return (PenLineCap)GetValue(ScaleEndCapProperty); }
+ set { SetValue(ScaleEndCapProperty, value); }
+ }
+
+ ///
+ /// Gets or sets the brush for the displayed value.
+ ///
+ public Brush ValueBrush
+ {
+ get { return (Brush)GetValue(ValueBrushProperty); }
+ set { SetValue(ValueBrushProperty, value); }
+ }
+
+ ///
+ /// Gets or sets the value string format.
+ ///
+ public string ValueStringFormat
+ {
+ get { return (string)GetValue(ValueStringFormatProperty); }
+ set { SetValue(ValueStringFormatProperty, value); }
+ }
+
+ ///
+ /// Gets or sets the start angle of the scale, which corresponds with the Minimum value, in degrees.
+ ///
+ public int MinAngle
+ {
+ get { return (int)GetValue(MinAngleProperty); }
+ set { SetValue(MinAngleProperty, value); }
+ }
+
+ ///
+ /// Gets or sets the end angle of the scale, which corresponds with the Maximum value, in degrees.
+ ///
+ public int MaxAngle
+ {
+ get { return (int)GetValue(MaxAngleProperty); }
+ set { SetValue(MaxAngleProperty, value); }
+ }
+
+ ///
+ /// Gets or sets the current angle of the needle (between MinAngle and MaxAngle). Setting the angle will update the Value.
+ ///
+ protected double ValueAngle
+ {
+ get { return (double)GetValue(ValueAngleProperty); }
+ set { SetValue(ValueAngleProperty, value); }
+ }
+
+ ///
+ /// Gets the normalized minimum angle.
+ ///
+ /// The minimum angle in the range from -180 to 180.
+ protected double NormalizedMinAngle => _normalizedMinAngle;
+
+ ///
+ /// Gets the normalized maximum angle.
+ ///
+ /// The maximum angle in the range from 180 to 540.
+ protected double NormalizedMaxAngle => _normalizedMaxAngle;
+
+ ///
+ /// Update the visual state of the control when its template is changed.
+ ///
+ protected override void OnApplyTemplate()
+ {
+ OnScaleChanged(this);
+
+ base.OnApplyTemplate();
+ }
+
+ private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ OnValueChanged(d);
+ }
+
+ private static void OnValueChanged(DependencyObject d)
+ {
+ var percentageRing = (RadialSlider)d;
+ if (!double.IsNaN(percentageRing.Value))
+ {
+ if (percentageRing.StepSize > 0)
+ {
+ percentageRing.Value = percentageRing.RoundToMultiple(percentageRing.Value, percentageRing.StepSize);
+ }
+
+ var middleOfScale = Radius - percentageRing.ScaleWidth / 2;
+ var valueText = percentageRing.GetTemplateChild(ValueTextPartName) as TextBlock;
+ percentageRing.ValueAngle = percentageRing.ValueToAngle(percentageRing.Value);
+
+ // Trail
+ var trail = percentageRing.GetTemplateChild(TrailPartName) as Path;
+ if (trail != null)
+ {
+ if (percentageRing.ValueAngle > percentageRing.NormalizedMinAngle)
+ {
+ trail.Visibility = Visibility.Visible;
+
+ if (percentageRing.ValueAngle - percentageRing.NormalizedMinAngle == 360)
+ {
+ // Draw full circle.
+ var eg = new EllipseGeometry
+ {
+ Center = new Point(Radius, Radius),
+ RadiusX = Radius - (percentageRing.ScaleWidth / 2)
+ };
+
+ eg.RadiusY = eg.RadiusX;
+ trail.Data = eg;
+ }
+ else
+ {
+ trail.StrokeStartLineCap = percentageRing.TrailStartCap;
+ trail.StrokeEndLineCap = percentageRing.TrailEndCap;
+
+ // Draw arc.
+ var pg = new PathGeometry();
+ var pf = new PathFigure
+ {
+ IsClosed = false,
+ StartPoint = percentageRing.ScalePoint(percentageRing.NormalizedMinAngle, middleOfScale)
+ };
+
+ var seg = new ArcSegment
+ {
+ SweepDirection = SweepDirection.Clockwise,
+ IsLargeArc = percentageRing.ValueAngle > 180 + percentageRing.NormalizedMinAngle,
+ Size = new Size(middleOfScale, middleOfScale),
+ Point =
+ percentageRing.ScalePoint(
+ Math.Min(percentageRing.ValueAngle, percentageRing.NormalizedMaxAngle), middleOfScale)
+ };
+
+ pf.Segments.Add(seg);
+ pg.Figures.Add(pf);
+ trail.Data = pg;
+ }
+ }
+ else
+ {
+ trail.Visibility = Visibility.Collapsed;
+ }
+ }
+
+ // Value Text
+ if (valueText != null)
+ {
+ valueText.Text = percentageRing.Value.ToString(percentageRing.ValueStringFormat);
+ }
+ }
+ }
+
+ private static void OnInteractivityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var percentageRing = (RadialSlider)d;
+
+ if (percentageRing.IsInteractive)
+ {
+ percentageRing.Tapped += percentageRing.RadialSlider_Tapped;
+ percentageRing.ManipulationDelta += percentageRing.RadialSlider_ManipulationDelta;
+ percentageRing.ManipulationCompleted += percentageRing.PercentageRingOnManipulationCompleted;
+ percentageRing.ManipulationMode = ManipulationModes.TranslateX | ManipulationModes.TranslateY;
+ }
+ else
+ {
+ percentageRing.Tapped -= percentageRing.RadialSlider_Tapped;
+ percentageRing.ManipulationCompleted -= percentageRing.PercentageRingOnManipulationCompleted;
+ percentageRing.ManipulationDelta -= percentageRing.RadialSlider_ManipulationDelta;
+ percentageRing.ManipulationMode = ManipulationModes.None;
+ }
+ }
+
+ private static void OnScaleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ OnScaleChanged(d);
+ }
+
+ private static void OnScaleChanged(DependencyObject d)
+ {
+ var percentageRing = (RadialSlider)d;
+
+ percentageRing.UpdateNormalizedAngles();
+
+ var scale = percentageRing.GetTemplateChild(ScalePartName) as Path;
+ if (scale != null)
+ {
+ if (percentageRing.NormalizedMaxAngle - percentageRing.NormalizedMinAngle == 360)
+ {
+ // Draw full circle.
+ var eg = new EllipseGeometry
+ {
+ Center = new Point(Radius, Radius),
+ RadiusX = Radius - (percentageRing.ScaleWidth / 2)
+ };
+
+ eg.RadiusY = eg.RadiusX;
+ scale.Data = eg;
+ }
+ else
+ {
+ scale.StrokeStartLineCap = percentageRing.ScaleStartCap;
+ scale.StrokeEndLineCap = percentageRing.ScaleEndCap;
+
+ // Draw arc.
+ var pg = new PathGeometry();
+ var pf = new PathFigure { IsClosed = false };
+ var middleOfScale = Radius - (percentageRing.ScaleWidth / 2);
+ pf.StartPoint = percentageRing.ScalePoint(percentageRing.NormalizedMinAngle, middleOfScale);
+ var seg = new ArcSegment
+ {
+ SweepDirection = SweepDirection.Clockwise,
+ IsLargeArc = percentageRing.NormalizedMaxAngle > (percentageRing.NormalizedMinAngle + 180),
+ Size = new Size(middleOfScale, middleOfScale),
+ Point = percentageRing.ScalePoint(percentageRing.NormalizedMaxAngle, middleOfScale)
+ };
+
+ pf.Segments.Add(seg);
+ pg.Figures.Add(pf);
+ scale.Data = pg;
+ }
+ }
+
+ OnValueChanged(percentageRing);
+ }
+
+ private void UpdateNormalizedAngles()
+ {
+ var result = Mod(MinAngle, 360);
+
+ if (result >= 180)
+ {
+ result = result - 360;
+ }
+
+ _normalizedMinAngle = result;
+
+ result = Mod(MaxAngle, 360);
+
+ if (result < 180)
+ {
+ result = result + 360;
+ }
+
+ if (result > NormalizedMinAngle + 360)
+ {
+ result = result - 360;
+ }
+
+ _normalizedMaxAngle = result;
+ }
+
+ private void RadialSlider_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
+ {
+ SetValueFromPoint(e.Position);
+ }
+
+ private void PercentageRingOnManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
+ {
+ ValueChanged?.Invoke(this, EventArgs.Empty);
+ }
+
+ private void RadialSlider_Tapped(object sender, TappedRoutedEventArgs e)
+ {
+ SetValueFromPoint(e.GetPosition(this));
+ ValueChanged?.Invoke(this, EventArgs.Empty);
+ }
+
+ private void SetValueFromPoint(Point p)
+ {
+ var pt = new Point(p.X - (ActualWidth / 2), -p.Y + (ActualHeight / 2));
+
+ var angle = Math.Atan2(pt.X, pt.Y) / Degrees2Radians;
+ var divider = Mod(NormalizedMaxAngle - NormalizedMinAngle, 360);
+ if (divider == 0)
+ {
+ divider = 360;
+ }
+
+ var value = Minimum + ((Maximum - Minimum) * (Mod(angle - NormalizedMinAngle, 360)) / divider);
+ if (value < Minimum || value > Maximum)
+ {
+ // Ignore positions outside the scale angle.
+ return;
+ }
+
+ Value = value;
+ }
+
+ private Point ScalePoint(double angle, double middleOfScale)
+ {
+ return new Point(Radius + (Math.Sin(Degrees2Radians * angle) * middleOfScale), Radius - (Math.Cos(Degrees2Radians * angle) * middleOfScale));
+ }
+
+ private double ValueToAngle(double value)
+ {
+ // Off-scale on the left.
+ if (value < Minimum)
+ {
+ return MinAngle;
+ }
+
+ // Off-scale on the right.
+ if (value > Maximum)
+ {
+ return MaxAngle;
+ }
+
+ return ((value - Minimum) / (Maximum - Minimum) * (NormalizedMaxAngle - NormalizedMinAngle)) + NormalizedMinAngle;
+ }
+
+ private double RoundToMultiple(double number, double multiple)
+ {
+ var modulo = number % multiple;
+ if ((multiple - modulo) <= modulo)
+ {
+ modulo = multiple - modulo;
+ }
+ else
+ {
+ modulo *= -1;
+ }
+
+ return number + modulo;
+ }
+
+ private static double Mod(double number, double divider)
+ {
+ var result = number % divider;
+ result = result < 0 ? result + divider : result;
+ return result;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/OpenHAB.Windows/Controls/RollershutterWidget.xaml b/OpenHAB.Windows/Controls/RollershutterWidget.xaml
new file mode 100644
index 00000000..6c6a3ee9
--- /dev/null
+++ b/OpenHAB.Windows/Controls/RollershutterWidget.xaml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/OpenHAB.Windows/Controls/RollershutterWidget.xaml.cs b/OpenHAB.Windows/Controls/RollershutterWidget.xaml.cs
new file mode 100644
index 00000000..7aac8141
--- /dev/null
+++ b/OpenHAB.Windows/Controls/RollershutterWidget.xaml.cs
@@ -0,0 +1,41 @@
+using GalaSoft.MvvmLight.Messaging;
+using OpenHAB.Core.Messages;
+using OpenHAB.Core.Model;
+using Windows.UI.Xaml;
+
+namespace OpenHAB.Windows.Controls
+{
+ ///
+ /// Widget control that represents an OpenHAB switch
+ ///
+ public sealed partial class RollershutterWidget : WidgetBase
+ {
+ ///
+ /// Gets or sets a value indicating whether the switch is on or off
+ ///
+ public bool IsOn { get; set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public RollershutterWidget()
+ {
+ InitializeComponent();
+ }
+
+ private void ButtonUp_Click(object sender, RoutedEventArgs e)
+ {
+ Messenger.Default.Send(new TriggerCommandMessage(Widget.Item, OpenHABCommands.UpCommand));
+ }
+
+ private void ButtonStop_Click(object sender, RoutedEventArgs e)
+ {
+ Messenger.Default.Send(new TriggerCommandMessage(Widget.Item, OpenHABCommands.StopCommand));
+ }
+
+ private void ButtonDown_Click(object sender, RoutedEventArgs e)
+ {
+ Messenger.Default.Send(new TriggerCommandMessage(Widget.Item, OpenHABCommands.DownCommand));
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenHAB.Windows/Controls/SectionSwitchWidget.xaml b/OpenHAB.Windows/Controls/SectionSwitchWidget.xaml
new file mode 100644
index 00000000..95e3ccfc
--- /dev/null
+++ b/OpenHAB.Windows/Controls/SectionSwitchWidget.xaml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/OpenHAB.Windows/Controls/SectionSwitchWidget.xaml.cs b/OpenHAB.Windows/Controls/SectionSwitchWidget.xaml.cs
new file mode 100644
index 00000000..c63d350d
--- /dev/null
+++ b/OpenHAB.Windows/Controls/SectionSwitchWidget.xaml.cs
@@ -0,0 +1,16 @@
+namespace OpenHAB.Windows.Controls
+{
+ ///
+ /// Widget control that represents an OpenHAB switch
+ ///
+ public sealed partial class SectionSwitchWidget : WidgetBase
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public SectionSwitchWidget()
+ {
+ InitializeComponent();
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenHAB.Windows/Controls/SliderWidget.xaml b/OpenHAB.Windows/Controls/SliderWidget.xaml
index b2ab8a5f..6d635318 100644
--- a/OpenHAB.Windows/Controls/SliderWidget.xaml
+++ b/OpenHAB.Windows/Controls/SliderWidget.xaml
@@ -1,59 +1,43 @@
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
diff --git a/OpenHAB.Windows/Controls/SliderWidget.xaml.cs b/OpenHAB.Windows/Controls/SliderWidget.xaml.cs
index 609673ff..2335a40b 100644
--- a/OpenHAB.Windows/Controls/SliderWidget.xaml.cs
+++ b/OpenHAB.Windows/Controls/SliderWidget.xaml.cs
@@ -1,8 +1,7 @@
-using System.Globalization;
+using System;
+using System.Globalization;
using GalaSoft.MvvmLight.Messaging;
using OpenHAB.Core.Messages;
-using Windows.UI.Xaml.Controls;
-using Windows.UI.Xaml.Input;
namespace OpenHAB.Windows.Controls
{
@@ -19,9 +18,14 @@ public SliderWidget()
InitializeComponent();
}
- private void Slider_OnPointerCaptureLost(object sender, PointerRoutedEventArgs e)
+ private void RadialSlider_OnValueChanged(object sender, EventArgs e)
{
- Messenger.Default.Send(new TriggerCommandMessage(Widget.Item, ((Slider)sender)?.Value.ToString(CultureInfo.InvariantCulture)));
+ if (Widget == null)
+ {
+ return;
+ }
+
+ Messenger.Default.Send(new TriggerCommandMessage(Widget.Item, ((RadialSlider)sender)?.Value.ToString(CultureInfo.InvariantCulture)));
}
}
}
diff --git a/OpenHAB.Windows/Controls/SwitchWidget.xaml b/OpenHAB.Windows/Controls/SwitchWidget.xaml
index 511f230a..feec8241 100644
--- a/OpenHAB.Windows/Controls/SwitchWidget.xaml
+++ b/OpenHAB.Windows/Controls/SwitchWidget.xaml
@@ -1,18 +1,85 @@
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/OpenHAB.Windows/Controls/SwitchWidget.xaml.cs b/OpenHAB.Windows/Controls/SwitchWidget.xaml.cs
index c2196825..61703b6c 100644
--- a/OpenHAB.Windows/Controls/SwitchWidget.xaml.cs
+++ b/OpenHAB.Windows/Controls/SwitchWidget.xaml.cs
@@ -2,7 +2,7 @@
using OpenHAB.Core.Messages;
using OpenHAB.Core.Model;
using Windows.UI.Xaml;
-using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Input;
namespace OpenHAB.Windows.Controls
{
@@ -11,17 +11,37 @@ namespace OpenHAB.Windows.Controls
///
public sealed partial class SwitchWidget : WidgetBase
{
+ ///
+ /// Gets or sets a value indicating whether the switch is on or off
+ ///
+ public bool IsOn { get; set; }
+
///
/// Initializes a new instance of the class.
///
public SwitchWidget()
{
InitializeComponent();
+ Loaded += SwitchWidget_Loaded;
+ }
+
+ private void SwitchWidget_Loaded(object sender, RoutedEventArgs e)
+ {
+ IsOn = Widget.Item.State == "ON";
+
+ VisualStateManager.GoToState(this, IsOn ? "OnState" : "OffState", false);
+ }
+
+ private void OnToggle()
+ {
+ IsOn = !IsOn;
+ Messenger.Default.Send(new TriggerCommandMessage(Widget.Item, IsOn ? OpenHABCommands.OnCommand : OpenHABCommands.OffCommand));
}
- private void ToggleSwitch_OnToggled(object sender, RoutedEventArgs e)
+ private void OnToggle(object sender, TappedRoutedEventArgs e)
{
- Messenger.Default.Send(new TriggerCommandMessage(Widget.Item, ((ToggleSwitch)sender).IsOn ? OpenHABCommands.OnCommand : OpenHABCommands.OffCommand));
+ OnToggle();
+ VisualStateManager.GoToState(this, ToggleStates.CurrentState == OnState ? "OffState" : "OnState", true);
}
}
}
\ No newline at end of file
diff --git a/OpenHAB.Windows/Controls/TextWidget.xaml b/OpenHAB.Windows/Controls/TextWidget.xaml
index 8f2089d6..120bd7c3 100644
--- a/OpenHAB.Windows/Controls/TextWidget.xaml
+++ b/OpenHAB.Windows/Controls/TextWidget.xaml
@@ -8,8 +8,24 @@
d:DesignWidth="400"
mc:Ignorable="d">
-
-
-
+
+
+
+
+
+
+
+
+
-
+
\ No newline at end of file
diff --git a/OpenHAB.Windows/Converters/BoolToBackgroundColorConverter.cs b/OpenHAB.Windows/Converters/BoolToBackgroundColorConverter.cs
new file mode 100644
index 00000000..1b4514ca
--- /dev/null
+++ b/OpenHAB.Windows/Converters/BoolToBackgroundColorConverter.cs
@@ -0,0 +1,19 @@
+using System;
+using Windows.UI.Xaml.Data;
+
+namespace OpenHAB.Windows.Converters
+{
+ public class BoolToBackgroundColorConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, string language)
+ {
+ //throw new NotImplementedException();
+ return null;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, string language)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/OpenHAB.Windows/Converters/IconToBitmapConverter.cs b/OpenHAB.Windows/Converters/IconToBitmapConverter.cs
new file mode 100644
index 00000000..ae690f64
--- /dev/null
+++ b/OpenHAB.Windows/Converters/IconToBitmapConverter.cs
@@ -0,0 +1,34 @@
+using System;
+using Microsoft.Practices.ServiceLocation;
+using OpenHAB.Core.Common;
+using OpenHAB.Core.Contracts.Services;
+using OpenHAB.Core.Model;
+using Windows.UI.Xaml.Data;
+using Windows.UI.Xaml.Media.Imaging;
+
+namespace OpenHAB.Windows.Converters
+{
+ ///
+ /// Converts an icon path to a bitmap object
+ ///
+ public class IconToBitmapConverter : IValueConverter
+ {
+ ///
+ public object Convert(object value, Type targetType, object parameter, string language)
+ {
+ var settingsService = ServiceLocator.Current.GetInstance();
+ var settings = settingsService.Load();
+ var serverUrl = settings.IsRunningInDemoMode.Value ? Constants.Api.DemoModeUrl : settings.OpenHABUrl;
+
+ string url = settingsService.ServerVersion == OpenHABVersion.Two ? $"{serverUrl}icon/{value}?state=UNDEF&format=png" : $"{serverUrl}images/{value}.png";
+
+ return new BitmapImage(new Uri(url));
+ }
+
+ ///
+ public object ConvertBack(object value, Type targetType, object parameter, string language)
+ {
+ throw new NotSupportedException();
+ }
+ }
+}
diff --git a/OpenHAB.Windows/Converters/IconToPathConverter.cs b/OpenHAB.Windows/Converters/IconToPathConverter.cs
index 5fa33f3e..f5af6692 100644
--- a/OpenHAB.Windows/Converters/IconToPathConverter.cs
+++ b/OpenHAB.Windows/Converters/IconToPathConverter.cs
@@ -1,6 +1,8 @@
using System;
using Microsoft.Practices.ServiceLocation;
+using OpenHAB.Core.Common;
using OpenHAB.Core.Contracts.Services;
+using OpenHAB.Core.Model;
using Windows.UI.Xaml.Data;
namespace OpenHAB.Windows.Converters
@@ -13,9 +15,13 @@ public class IconToPathConverter : IValueConverter
///
public object Convert(object value, Type targetType, object parameter, string language)
{
- string serverUrl = ServiceLocator.Current.GetInstance().Load().OpenHABUrl;
+ var settingsService = ServiceLocator.Current.GetInstance();
+ var settings = settingsService.Load();
+ var serverUrl = settings.IsRunningInDemoMode.Value ? Constants.Api.DemoModeUrl : settings.OpenHABUrl;
- return $"{serverUrl}/images/{value}.png";
+ return settingsService.ServerVersion == OpenHABVersion.Two ?
+ $"{serverUrl}icon/{value}?state=UNDEF&format=png" :
+ $"{serverUrl}images/{value}.png";
}
///
diff --git a/OpenHAB.Windows/Converters/ReverseBoolConverter.cs b/OpenHAB.Windows/Converters/ReverseBoolConverter.cs
new file mode 100644
index 00000000..ebce6eea
--- /dev/null
+++ b/OpenHAB.Windows/Converters/ReverseBoolConverter.cs
@@ -0,0 +1,30 @@
+using System;
+using Windows.UI.Xaml.Data;
+
+namespace OpenHAB.Windows.Converters
+{
+ ///
+ /// Reverses the value of a boolean
+ ///
+ public class ReverseBoolConverter : IValueConverter
+ {
+ ///
+ public object Convert(object value, Type targetType, object parameter, string language)
+ {
+ if (value == null)
+ {
+ return false;
+ }
+
+ bool convertedValue = (bool)value;
+
+ return !convertedValue;
+ }
+
+ ///
+ public object ConvertBack(object value, Type targetType, object parameter, string language)
+ {
+ throw new NotSupportedException();
+ }
+ }
+}
diff --git a/OpenHAB.Windows/Converters/StringToDoubleConverter.cs b/OpenHAB.Windows/Converters/StringToDoubleConverter.cs
new file mode 100644
index 00000000..cdfc1d98
--- /dev/null
+++ b/OpenHAB.Windows/Converters/StringToDoubleConverter.cs
@@ -0,0 +1,27 @@
+using System;
+using Windows.UI.Xaml.Data;
+
+namespace OpenHAB.Windows.Converters
+{
+ ///
+ /// Converts a string to a double, returning 0 if the string is invalid
+ ///
+ public class StringToDoubleConverter : IValueConverter
+ {
+ ///
+ public object Convert(object value, Type targetType, object parameter, string language)
+ {
+ string valueString = value.ToString();
+ double valueDouble;
+
+ double.TryParse(valueString, out valueDouble);
+ return valueDouble;
+ }
+
+ ///
+ public object ConvertBack(object value, Type targetType, object parameter, string language)
+ {
+ throw new NotSupportedException();
+ }
+ }
+}
diff --git a/OpenHAB.Windows/Converters/WidgetTemplateSelector.cs b/OpenHAB.Windows/Converters/WidgetTemplateSelector.cs
index 89e85004..8da3ad09 100644
--- a/OpenHAB.Windows/Converters/WidgetTemplateSelector.cs
+++ b/OpenHAB.Windows/Converters/WidgetTemplateSelector.cs
@@ -1,4 +1,5 @@
-using OpenHAB.Core.Model;
+using System.Linq;
+using OpenHAB.Core.Model;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
@@ -13,25 +14,39 @@ public class WidgetTemplateSelector : DataTemplateSelector
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
var widget = item as OpenHABWidget;
+ var uiElement = container as UIElement;
if (widget == null)
{
- return FrameTemplate;
+ return null;
}
- switch (widget.Type.ToLower())
+ var itemType = GetItemViewType(widget);
+ switch (itemType)
{
+ case "group":
+ return PageLinkTemplate;
case "frame":
+ VariableSizedWrapGrid.SetRowSpan(uiElement, widget.Children.Count + 1);
return FrameTemplate;
case "switch":
return SwitchTemplate;
+ case "rollershutter":
+ return RollershutterTemplate;
case "slider":
return SliderTemplate;
+ case "datetime":
case "text":
- case "numberitem":
return TextTemplate;
+ //case "color":
+ // return ColorTemplate;
case "image":
return ImageTemplate;
+ case "sectionswitch":
+ return SectionSwitchTemplate;
+ case "video_mjpeg":
+ case "video":
+ return MjpegTemplate;
default:
return FrameTemplate;
}
@@ -42,6 +57,21 @@ protected override DataTemplate SelectTemplateCore(object item, DependencyObject
///
public DataTemplate FrameTemplate { get; set; }
+ ///
+ /// Gets or sets the template for a MJPEG video control
+ ///
+ public DataTemplate MjpegTemplate { get; set; }
+
+ ///
+ /// Gets or sets the template for a rollershutter control
+ ///
+ public DataTemplate RollershutterTemplate { get; set; }
+
+ ///
+ /// Gets or sets the template for a Pagelink control
+ ///
+ public DataTemplate PageLinkTemplate { get; set; }
+
///
/// Gets or sets the template for a Switch control
///
@@ -61,5 +91,113 @@ protected override DataTemplate SelectTemplateCore(object item, DependencyObject
/// Gets or sets the template for a Image control
///
public DataTemplate ImageTemplate { get; set; }
+
+ ///
+ /// Gets or sets the template for a section switch control
+ ///
+ public DataTemplate SectionSwitchTemplate { get; set; }
+
+ ///
+ /// Gets or sets the template for a color picker control
+ ///
+ public DataTemplate ColorTemplate { get; set; }
+
+ private string GetItemViewType(OpenHABWidget openHABWidget)
+ {
+ if (openHABWidget.Type.Equals("Frame"))
+ {
+ return "frame";
+ }
+
+ if (openHABWidget.Type.Equals("Group"))
+ {
+ return "group";
+ }
+
+ if (openHABWidget.Type.Equals("Switch"))
+ {
+ if (openHABWidget.Mappings != null && openHABWidget.Mappings.Any())
+ {
+ return "sectionswitch";
+ }
+
+ if (openHABWidget.Item != null)
+ {
+ if (openHABWidget.Item.Type != null)
+ {
+ // RollerShutterItem changed to RollerShutter in later builds of OH2
+ if ("RollershutterItem".Equals(openHABWidget.Item.Type) ||
+ "Rollershutter".Equals(openHABWidget.Item.Type) ||
+ "Rollershutter".Equals(openHABWidget.Item.GroupType))
+ {
+ return "rollershutter";
+ }
+
+ return "switch";
+ }
+
+ return "switch";
+ }
+
+ return "switch";
+ }
+
+ if (openHABWidget.Type.Equals("Text"))
+ {
+ return "text";
+ }
+
+ if (openHABWidget.Type.Equals("Slider"))
+ {
+ return "slider";
+ }
+
+ if (openHABWidget.Type.Equals("Image"))
+ {
+ return "image";
+ }
+
+ if (openHABWidget.Type.Equals("Selection"))
+ {
+ return "selection";
+ }
+
+ if (openHABWidget.Type.Equals("Setpoint"))
+ {
+ return "setpoint";
+ }
+
+ if (openHABWidget.Type.Equals("Chart"))
+ {
+ return "chart";
+ }
+
+ if (openHABWidget.Type.Equals("Video"))
+ {
+ if (openHABWidget.Encoding != null)
+ {
+ if (openHABWidget.Encoding.Equals("mjpeg"))
+ {
+ return "video_mjpeg";
+ }
+
+ return "video";
+ }
+
+ return "video";
+ }
+
+ if (openHABWidget.Type.Equals("Webview"))
+ {
+ return "web";
+ }
+
+ if (openHABWidget.Type.Equals("Colorpicker"))
+ {
+ return "color";
+ }
+
+ return "generic";
+ }
}
-}
+}
\ No newline at end of file
diff --git a/OpenHAB.Windows/GlobalSuppressions.cs b/OpenHAB.Windows/GlobalSuppressions.cs
new file mode 100644
index 00000000..558e7dfe
--- /dev/null
+++ b/OpenHAB.Windows/GlobalSuppressions.cs
@@ -0,0 +1,10 @@
+// This file is used by Code Analysis to maintain SuppressMessage
+// attributes that are applied to this project.
+// Project-level suppressions either have no target or are given
+// a specific target and scoped to a namespace, type, member, etc.
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1507:Code must not contain multiple blank lines in a row", Justification = "", Scope = "member", Target = "~M:OpenHAB.Windows.Converters.WidgetTemplateSelector.GetItemViewType(OpenHAB.Core.Model.OpenHABWidget)~System.String")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1407:Arithmetic expressions must declare precedence", Justification = "", Scope = "member", Target = "~M:OpenHAB.Windows.Controls.RadialSlider.ScalePoint(System.Double,System.Double)~Windows.Foundation.Point")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1407:Arithmetic expressions must declare precedence", Justification = "", Scope = "member", Target = "~M:OpenHAB.Windows.Controls.RadialSlider.ValueToAngle(System.Double)~System.Double")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1407:Arithmetic expressions must declare precedence", Justification = "", Scope = "member", Target = "~M:OpenHAB.Windows.Controls.RadialSlider.OnApplyTemplate")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1407:Arithmetic expressions must declare precedence", Justification = "", Scope = "member", Target = "~M:OpenHAB.Windows.Controls.RadialSlider.OnValueChanged(Windows.UI.Xaml.DependencyObject)")]
diff --git a/OpenHAB.Windows/OpenHAB.Windows.csproj b/OpenHAB.Windows/OpenHAB.Windows.csproj
index ace44080..59d4a39f 100644
--- a/OpenHAB.Windows/OpenHAB.Windows.csproj
+++ b/OpenHAB.Windows/OpenHAB.Windows.csproj
@@ -12,11 +12,15 @@
en-US
UAP
10.0.14393.0
- 10.0.10586.0
+ 10.0.14393.0
14
512
{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- Openhab.UWP_TemporaryKey.pfx
+ OpenHAB.Windows_StoreKey.pfx
+ 020B1A413FF10125AC5FA8C8BCE617F406E35A86
+ True
+ Always
+ x86|x64|arm
true
@@ -97,36 +101,64 @@
+
App.xaml
+
+ ChartWidget.xaml
+
+
+ ColorMap.xaml
+
FrameWidget.xaml
ImageLabel.xaml
+
+ MjpegWidget.xaml
+
ImageWidget.xaml
+
SliderWidget.xaml
+
+ PageLinkWidget.xaml
+
+
+ RollershutterWidget.xaml
+
+
+ SectionSwitchWidget.xaml
+
SwitchWidget.xaml
+
+ ColorWidget.xaml
+
TextWidget.xaml
+
+
+
+
+
MainPage.xaml
@@ -142,7 +174,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -157,6 +232,14 @@
MSBuild:Compile
Designer
+
+ MSBuild:Compile
+ Designer
+
+
+ MSBuild:Compile
+ Designer
+
Designer
MSBuild:Compile
@@ -165,6 +248,10 @@
Designer
MSBuild:Compile
+
+ MSBuild:Compile
+ Designer
+
Designer
MSBuild:Compile
@@ -173,14 +260,34 @@
MSBuild:Compile
Designer
+
+ MSBuild:Compile
+ Designer
+
+
+ MSBuild:Compile
+ Designer
+
+
+ MSBuild:Compile
+ Designer
+
Designer
MSBuild:Compile
+
+ MSBuild:Compile
+ Designer
+
Designer
MSBuild:Compile
+
+ MSBuild:Compile
+ Designer
+
MSBuild:Compile
Designer
@@ -206,6 +313,14 @@
OpenHAB.Core
+
+
+ Windows Desktop Extensions for the UWP
+
+
+ Windows Mobile Extensions for the UWP
+
+
14.0
diff --git a/OpenHAB.Windows/Package.StoreAssociation.xml b/OpenHAB.Windows/Package.StoreAssociation.xml
new file mode 100644
index 00000000..17292492
--- /dev/null
+++ b/OpenHAB.Windows/Package.StoreAssociation.xml
@@ -0,0 +1,368 @@
+
+
+ CN=8A77D062-E996-4F32-9CC6-50568ABAFF8F
+ openHAB Foundation e.V.
+ http://www.w3.org/2001/04/xmlenc#sha256
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ openHABFoundatione.V.openHAB
+
+ openHAB
+
+
+
+
+
\ No newline at end of file
diff --git a/OpenHAB.Windows/Package.appxmanifest b/OpenHAB.Windows/Package.appxmanifest
index d7f8b479..bf10fa72 100644
--- a/OpenHAB.Windows/Package.appxmanifest
+++ b/OpenHAB.Windows/Package.appxmanifest
@@ -1,49 +1,29 @@
-
-
-
-
-
-
-
+
+
+
- OpenHAB.Windows
- NVMWY41
- Assets\StoreLogo.png
+ openHAB
+ openHAB Foundation e.V.
+ Assets\NewStoreLogo.png
-
-
-
+
-
-
-
-
-
+
+
+
+
+
-
+
\ No newline at end of file
diff --git a/OpenHAB.Windows/Styles/DefaultTheme.xaml b/OpenHAB.Windows/Styles/DefaultTheme.xaml
index ae2d6e9e..ed4b5869 100644
--- a/OpenHAB.Windows/Styles/DefaultTheme.xaml
+++ b/OpenHAB.Windows/Styles/DefaultTheme.xaml
@@ -1,11 +1,383 @@
-
+
+
#FFFF5722
#EEEEEE
+
+
+ #344040
+ #C0C0C0
+
+
-
-
diff --git a/OpenHAB.Windows/Themes/Generic.xaml b/OpenHAB.Windows/Themes/Generic.xaml
new file mode 100644
index 00000000..64d01b1c
--- /dev/null
+++ b/OpenHAB.Windows/Themes/Generic.xaml
@@ -0,0 +1,49 @@
+
+
+
+
\ No newline at end of file
diff --git a/OpenHAB.Windows/View/MainPage.xaml b/OpenHAB.Windows/View/MainPage.xaml
index a79ec40e..63492206 100644
--- a/OpenHAB.Windows/View/MainPage.xaml
+++ b/OpenHAB.Windows/View/MainPage.xaml
@@ -11,134 +11,152 @@
mc:Ignorable="d">
-
+
-
+
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
+
+
+
+
-
+
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
-
+ ItemsSource="{x:Bind Vm.CurrentWidgets, Mode=OneWay}"
+ SelectionMode="None">
+
+
+
+
+
+
+
+
+
+
diff --git a/OpenHAB.Windows/View/MainPage.xaml.cs b/OpenHAB.Windows/View/MainPage.xaml.cs
index 4372ec5d..026b5b3e 100644
--- a/OpenHAB.Windows/View/MainPage.xaml.cs
+++ b/OpenHAB.Windows/View/MainPage.xaml.cs
@@ -1,4 +1,9 @@
-using OpenHAB.Core.ViewModel;
+using GalaSoft.MvvmLight.Messaging;
+using OpenHAB.Core.Messages;
+using OpenHAB.Core.Model;
+using OpenHAB.Core.Services;
+using OpenHAB.Core.ViewModel;
+using Windows.UI.Core;
using Windows.UI.Xaml.Controls;
namespace OpenHAB.Windows.View
@@ -19,6 +24,19 @@ public sealed partial class MainPage : Page
public MainPage()
{
InitializeComponent();
+ Vm.CurrentWidgets.CollectionChanged += (sender, args) =>
+ {
+ SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = WidgetNavigationService.CanGoBack
+ ? AppViewBackButtonVisibility.Visible
+ : AppViewBackButtonVisibility.Collapsed;
+ };
+
+ SystemNavigationManager.GetForCurrentView().BackRequested += (sender, args) => Vm.WidgetGoBack();
+ }
+
+ private void MasterListView_OnItemClick(object sender, ItemClickEventArgs e)
+ {
+ Messenger.Default.Send(new WidgetClickedMessage(e.ClickedItem as OpenHABWidget));
}
}
}
diff --git a/OpenHAB.Windows/View/SettingsPage.xaml b/OpenHAB.Windows/View/SettingsPage.xaml
index 08e64aab..8a21833c 100644
--- a/OpenHAB.Windows/View/SettingsPage.xaml
+++ b/OpenHAB.Windows/View/SettingsPage.xaml
@@ -1,81 +1,106 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/OpenHAB.Windows/View/SettingsPage.xaml.cs b/OpenHAB.Windows/View/SettingsPage.xaml.cs
index a65b24e6..f7b96623 100644
--- a/OpenHAB.Windows/View/SettingsPage.xaml.cs
+++ b/OpenHAB.Windows/View/SettingsPage.xaml.cs
@@ -22,12 +22,10 @@ public SettingsPage()
InitializeComponent();
}
- private void SaveButton_OnClick(object sender, RoutedEventArgs e)
+
+ private void ButtonCancel_OnClick(object sender, RoutedEventArgs e)
{
- if (Frame.CanGoBack)
- {
- Frame.GoBack();
- }
+ Frame.GoBack();
}
}
}
diff --git a/OpenHAB.Windows/_pkginfo.txt b/OpenHAB.Windows/_pkginfo.txt
new file mode 100644
index 00000000..b3e2bdaf
--- /dev/null
+++ b/OpenHAB.Windows/_pkginfo.txt
@@ -0,0 +1 @@
+C:\Users\nvmwy41\Source\Repos\openhab.windows\OpenHAB.Windows\AppPackages\OpenHAB.Windows_0.1.6.0\OpenHAB.Windows_0.1.6.0_x86_x64_arm.appxbundle
diff --git a/OpenHAB.Windows/_scale-100.appx b/OpenHAB.Windows/_scale-100.appx
new file mode 100644
index 00000000..d1ffb964
Binary files /dev/null and b/OpenHAB.Windows/_scale-100.appx differ
diff --git a/OpenHAB.Windows/_scale-125.appx b/OpenHAB.Windows/_scale-125.appx
new file mode 100644
index 00000000..4a94b1a2
Binary files /dev/null and b/OpenHAB.Windows/_scale-125.appx differ
diff --git a/OpenHAB.Windows/_scale-150.appx b/OpenHAB.Windows/_scale-150.appx
new file mode 100644
index 00000000..c055325b
Binary files /dev/null and b/OpenHAB.Windows/_scale-150.appx differ
diff --git a/OpenHAB.Windows/_scale-400.appx b/OpenHAB.Windows/_scale-400.appx
new file mode 100644
index 00000000..424ba15f
Binary files /dev/null and b/OpenHAB.Windows/_scale-400.appx differ
diff --git a/OpenHAB.Windows/project.json b/OpenHAB.Windows/project.json
index 51b2e9b2..ae89af8d 100644
--- a/OpenHAB.Windows/project.json
+++ b/OpenHAB.Windows/project.json
@@ -1,10 +1,12 @@
{
"dependencies": {
"Microsoft.NETCore.UniversalWindowsPlatform": "5.2.2",
+ "Microsoft.Toolkit.Uwp.UI.Controls": "1.1.0",
"Microsoft.Xaml.Behaviors.Uwp.Managed": "1.1.0",
"MvvmLightLibs": "5.3.0",
"StyleCop.Analyzers": "1.0.0",
- "Unity": "4.0.1"
+ "Unity": "4.0.1",
+ "WinRTXamlToolkit.UWP": "2.0.0"
},
"frameworks": {
"uap10.0": {}
diff --git a/Openhab.Core/Common/ColorChangedEventArgs.cs b/Openhab.Core/Common/ColorChangedEventArgs.cs
new file mode 100644
index 00000000..70dc5eb7
--- /dev/null
+++ b/Openhab.Core/Common/ColorChangedEventArgs.cs
@@ -0,0 +1,25 @@
+using System;
+using Windows.UI;
+
+namespace OpenHAB.Core.Common
+{
+ ///
+ /// Event arguments for a color changed event
+ ///
+ public class ColorChangedEventArgs : EventArgs
+ {
+ ///
+ /// Gets or sets the newly selected color
+ ///
+ public Color SelectedColor { get; set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The color that was just selected
+ public ColorChangedEventArgs(Color selectedColor)
+ {
+ SelectedColor = selectedColor;
+ }
+ }
+}
diff --git a/Openhab.Core/Common/ColorHelper.cs b/Openhab.Core/Common/ColorHelper.cs
new file mode 100644
index 00000000..c4adff86
--- /dev/null
+++ b/Openhab.Core/Common/ColorHelper.cs
@@ -0,0 +1,169 @@
+using System;
+using System.Numerics;
+using Windows.UI;
+
+namespace OpenHAB.Core.Common
+{
+ ///
+ /// Helper methods for Color
+ ///
+ public static class ColorHelper
+ {
+ // http://stackoverflow.com/a/19338652/62857
+
+ ///
+ /// Converts an HSL color value to RGB.
+ /// Input: Vector4 ( X: [0.0, 1.0], Y: [0.0, 1.0], Z: [0.0, 1.0], W: [0.0, 1.0] )
+ /// Output: Color ( R: [0, 255], G: [0, 255], B: [0, 255], A: [0, 255] )
+ ///
+ /// Vector4 defining X = h, Y = s, Z = l, W = a. Ranges [0, 1.0]
+ /// RGBA Color. Ranges [0, 255]
+ public static Color FromHSL(Vector4 hsl)
+ {
+ float r, g, b;
+
+ if (hsl.Y == 0.0f)
+ {
+ r = g = b = hsl.Z;
+ }
+ else
+ {
+ var q = hsl.Z < 0.5f ? hsl.Z * (1.0f + hsl.Y) : hsl.Z + hsl.Y - hsl.Z * hsl.Y;
+ var p = 2.0f * hsl.Z - q;
+ r = HueToRgb(p, q, hsl.X + 1.0f / 3.0f);
+ g = HueToRgb(p, q, hsl.X);
+ b = HueToRgb(p, q, hsl.X - 1.0f / 3.0f);
+ }
+
+ return Color.FromArgb((byte)(hsl.W * 255), (byte)(r * 255), (byte)(g * 255), (byte)(b * 255));
+ }
+
+ // Helper for HslToRgba
+ private static float HueToRgb(float p, float q, float t)
+ {
+ if (t < 0.0f) t += 1.0f;
+ if (t > 1.0f) t -= 1.0f;
+ if (t < 1.0f / 6.0f) return p + (q - p) * 6.0f * t;
+ if (t < 1.0f / 2.0f) return q;
+ if (t < 2.0f / 3.0f) return p + (q - p) * (2.0f / 3.0f - t) * 6.0f;
+ return p;
+ }
+
+ ///
+ /// Converts an RGB color value to HSL.
+ /// Input: Color ( R: [0, 255], G: [0, 255], B: [0, 255], A: [0, 255] )
+ /// Output: Vector4 ( X: [0.0, 1.0], Y: [0.0, 1.0], Z: [0.0, 1.0], W: [0.0, 1.0] )
+ ///
+ ///
+ ///
+ public static Vector4 ToHSL(Color rgba)
+ {
+ float r = rgba.R / 255.0f;
+ float g = rgba.G / 255.0f;
+ float b = rgba.B / 255.0f;
+
+ float max = (r > g && r > b) ? r : (g > b) ? g : b;
+ float min = (r < g && r < b) ? r : (g < b) ? g : b;
+
+ float h, s, l;
+ h = s = l = (max + min) / 2.0f;
+
+ if (max == min)
+ h = s = 0.0f;
+
+ else
+ {
+ float delta = max - min;
+ s = (l > 0.5f) ? delta / (2.0f - max - min) : delta / (max + min);
+
+ if (r > g && r > b)
+ h = (g - b) / delta;
+
+ else if (g > b)
+ h = (b - r) / delta + 2.0f;
+
+ else
+ h = (r - g) / delta + 4.0f;
+
+ h /= 6.0f;
+ }
+ if (h < 0) h += 1f;
+
+ return new Vector4(h, s, l, rgba.A / 255.0f);
+ }
+
+ #region HSV
+
+ // from http://stackoverflow.com/a/1626175/62857
+
+ public static Vector4 ToHSV(Color color)
+ {
+ double hue;
+ double saturation;
+ double value;
+ ToHSV(color, out hue, out saturation, out value);
+ return new Vector4((byte)(hue * 255), (byte)(saturation * 255), (byte)(value * 255), color.A / 255.0f);
+ }
+
+ public static void ToHSV(Color rgba, out double hue, out double saturation, out double value)
+ {
+ int max = Math.Max(rgba.R, Math.Max(rgba.G, rgba.B));
+ int min = Math.Min(rgba.R, Math.Min(rgba.G, rgba.B));
+
+ //hue = color.GetHue();
+ var hsl = ToHSL(rgba);
+ hue = hsl.X;
+
+ saturation = (max == 0) ? 0 : 1d - (1d * min / max);
+ value = max / 255d;
+ }
+
+ public static Color FromHSV(Vector4 hsv)
+ {
+ var c = FromHSV(hsv.X, hsv.Y, hsv.Z);
+ c.A = (byte)(hsv.W * 255);
+ return c;
+ }
+
+ public static Color FromHSV(double hue, double saturation, double value)
+ {
+ int hi = Convert.ToInt32(Math.Floor(hue / 60)) % 6;
+ double f = (hue / 60) - Math.Floor(hue / 60);
+
+ value = value * 255;
+ byte v = (byte)value;
+ byte p = (byte)(value * (1 - saturation));
+ byte q = (byte)(value * (1 - (f * saturation)));
+ byte t = (byte)(value * (1 - ((1 - f) * saturation)));
+
+ if (hi == 0)
+ {
+ return Color.FromArgb(255, v, t, p);
+ }
+
+ if (hi == 1)
+ {
+ return Color.FromArgb(255, q, v, p);
+ }
+
+ if (hi == 2)
+ {
+ return Color.FromArgb(255, p, v, t);
+ }
+
+ if (hi == 3)
+ {
+ return Color.FromArgb(255, p, q, v);
+ }
+
+ if (hi == 4)
+ {
+ return Color.FromArgb(255, t, p, v);
+ }
+
+ return Color.FromArgb(255, v, p, q);
+ }
+
+ #endregion
+ }
+}
diff --git a/Openhab.Core/Common/Constants.cs b/Openhab.Core/Common/Constants.cs
index 4587b737..f6173972 100644
--- a/Openhab.Core/Common/Constants.cs
+++ b/Openhab.Core/Common/Constants.cs
@@ -21,6 +21,11 @@ public sealed class Local
///
public sealed class Api
{
+ ///
+ /// Url used for Demo mode
+ ///
+ public const string DemoModeUrl = "http://demo.openhab.org:8080/";
+
///
/// The call to determine the OpenHAB version
///
diff --git a/Openhab.Core/Common/ObservableCollectionExtensions.cs b/Openhab.Core/Common/ObservableCollectionExtensions.cs
new file mode 100644
index 00000000..d22fcbca
--- /dev/null
+++ b/Openhab.Core/Common/ObservableCollectionExtensions.cs
@@ -0,0 +1,33 @@
+using System.Collections.Generic;
+
+// ReSharper disable once CheckNamespace
+namespace System.Collections.ObjectModel
+{
+ ///
+ /// Collection of extensions for the ObservableCollection class
+ ///
+ public static class ObservableCollectionExtensions
+ {
+ ///
+ /// Adds a range of items to the observable collection
+ ///
+ /// The ObservableCollection
+ /// List of items to add
+ /// Type of items
+ /// The ObservableCollection, including the new range of items
+ public static ObservableCollection AddRange(this ObservableCollection target, IEnumerable range)
+ {
+ if (range == null)
+ {
+ return target;
+ }
+
+ foreach (var item in range)
+ {
+ target.Add(item);
+ }
+
+ return target;
+ }
+ }
+}
diff --git a/Openhab.Core/Common/OpenHABHttpClient.cs b/Openhab.Core/Common/OpenHABHttpClient.cs
index e3fba5c7..3d2298a5 100644
--- a/Openhab.Core/Common/OpenHABHttpClient.cs
+++ b/Openhab.Core/Common/OpenHABHttpClient.cs
@@ -1,5 +1,8 @@
using System;
+using System.Net;
using System.Net.Http;
+using Microsoft.Practices.ServiceLocation;
+using OpenHAB.Core.Contracts.Services;
namespace OpenHAB.Core.Common
{
@@ -24,6 +27,15 @@ public static HttpClient Client()
return _client ?? (_client = InitClient());
}
+ ///
+ /// Create an HttpClient instance for one-time use
+ ///
+ /// The HttpClient instance
+ public static HttpClient DisposableClient()
+ {
+ return InitClient(true);
+ }
+
///
/// Forces creation of a new client, for example when the settings in the app are updated
///
@@ -32,12 +44,44 @@ public static void ResetClient()
_client = null;
}
- private static HttpClient InitClient()
+ private static HttpClient InitClient(bool disposable = false)
+ {
+ if (string.IsNullOrWhiteSpace(BaseUrl) && !disposable)
+ {
+ return null;
+ }
+
+ var handler = new HttpClientHandler();
+
+ var credentials = GetCredentials();
+
+ if (credentials != null)
+ {
+ handler.Credentials = credentials;
+ }
+
+ var client = new HttpClient(handler);
+
+ if (!disposable)
+ {
+ client.BaseAddress = new Uri(BaseUrl);
+ }
+
+ return client;
+ }
+
+ private static NetworkCredential GetCredentials()
{
- return new HttpClient
+ var settings = ServiceLocator.Current.GetInstance().Load();
+ string username = settings.Username;
+ string password = settings.Password;
+
+ if (!string.IsNullOrWhiteSpace(username) && !string.IsNullOrWhiteSpace(password))
{
- BaseAddress = new Uri(BaseUrl)
- };
+ return new NetworkCredential(username, password);
+ }
+
+ return null;
}
}
}
diff --git a/Openhab.Core/Contracts/Services/ISettingsService.cs b/Openhab.Core/Contracts/Services/ISettingsService.cs
index a17521e3..8abf1ab8 100644
--- a/Openhab.Core/Contracts/Services/ISettingsService.cs
+++ b/Openhab.Core/Contracts/Services/ISettingsService.cs
@@ -8,6 +8,11 @@ namespace OpenHAB.Core.Contracts.Services
///
public interface ISettingsService
{
+ ///
+ /// Gets or sets the version of openHAB that's running on the server
+ ///
+ OpenHABVersion ServerVersion { get; set; }
+
///
/// Persists the current settings
///
diff --git a/Openhab.Core/Messages/WidgetClickedMessage.cs b/Openhab.Core/Messages/WidgetClickedMessage.cs
new file mode 100644
index 00000000..9e964d0e
--- /dev/null
+++ b/Openhab.Core/Messages/WidgetClickedMessage.cs
@@ -0,0 +1,24 @@
+using OpenHAB.Core.Model;
+
+namespace OpenHAB.Core.Messages
+{
+ ///
+ /// A message that fires whenever a widget is clicked on a sitemap
+ ///
+ public class WidgetClickedMessage
+ {
+ ///
+ /// Gets or sets the Widget property
+ ///
+ public OpenHABWidget Widget { get; set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The widget that was clicked
+ public WidgetClickedMessage(OpenHABWidget widget)
+ {
+ Widget = widget;
+ }
+ }
+}
diff --git a/Openhab.Core/Model/OpenHABCommands.cs b/Openhab.Core/Model/OpenHABCommands.cs
index 49a995c0..9d64c3ae 100644
--- a/Openhab.Core/Model/OpenHABCommands.cs
+++ b/Openhab.Core/Model/OpenHABCommands.cs
@@ -14,5 +14,20 @@ public sealed class OpenHABCommands
/// The command to toggle a switch OFF
///
public const string OffCommand = "OFF";
+
+ ///
+ /// The command to make a rollershutter go up
+ ///
+ public const string UpCommand = "UP";
+
+ ///
+ /// The command to make a rollershutter go down
+ ///
+ public const string DownCommand = "DOWN";
+
+ ///
+ /// The command to make a rollershutter stop
+ ///
+ public const string StopCommand = "STOP";
}
}
diff --git a/Openhab.Core/Model/OpenHABItem.cs b/Openhab.Core/Model/OpenHABItem.cs
index b8305695..92dbcde2 100644
--- a/Openhab.Core/Model/OpenHABItem.cs
+++ b/Openhab.Core/Model/OpenHABItem.cs
@@ -33,6 +33,13 @@ public class OpenHABItem
///
public string Link { get; set; }
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public OpenHABItem()
+ {
+ }
+
///
/// Initializes a new instance of the class.
///
diff --git a/Openhab.Core/Model/OpenHABSitemap.cs b/Openhab.Core/Model/OpenHABSitemap.cs
index bf0c2578..b0861890 100644
--- a/Openhab.Core/Model/OpenHABSitemap.cs
+++ b/Openhab.Core/Model/OpenHABSitemap.cs
@@ -40,6 +40,11 @@ public class OpenHABSitemap : ObservableBase
///
public bool Leaf { get; set; }
+ ///
+ /// Gets or sets the title of the sitemap
+ ///
+ public string Title { get; set; }
+
///
/// Gets or sets a collection of widgets of the OpenHAB sitemap
///
@@ -62,6 +67,13 @@ public ICollection Widgets
}
}
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public OpenHABSitemap()
+ {
+ }
+
///
/// Initializes a new instance of the class.
///
diff --git a/Openhab.Core/Model/OpenHABWidget.cs b/Openhab.Core/Model/OpenHABWidget.cs
index 4b86a9cb..e84cd294 100644
--- a/Openhab.Core/Model/OpenHABWidget.cs
+++ b/Openhab.Core/Model/OpenHABWidget.cs
@@ -1,5 +1,7 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Xml.Linq;
+using Newtonsoft.Json;
namespace OpenHAB.Core.Model
{
@@ -8,6 +10,9 @@ namespace OpenHAB.Core.Model
///
public class OpenHABWidget
{
+ private string _icon;
+ private string _label;
+
///
/// Gets or sets the ID of the OpenHAB widget
///
@@ -16,12 +21,44 @@ public class OpenHABWidget
///
/// Gets or sets the Label of the OpenHAB widget
///
- public string Label { get; set; }
+ public string Label
+ {
+ get
+ {
+ return _label;
+ }
+
+ set
+ {
+ if (value.Trim() == string.Empty)
+ {
+ _label = value;
+ return;
+ }
+
+ var parts = value.Split(new[] { "[", "]" }, StringSplitOptions.RemoveEmptyEntries);
+ _label = parts[0];
+
+ if (parts.Length > 1)
+ {
+ Value = parts[1];
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the Value of the widget
+ ///
+ public string Value { get; set; }
///
/// Gets or sets the Icon of the OpenHAB widget
///
- public string Icon { get; set; }
+ public string Icon
+ {
+ get { return _icon ?? string.Empty; }
+ set { _icon = value; }
+ }
///
/// Gets or sets the Type of the OpenHAB widget
@@ -76,17 +113,17 @@ public class OpenHABWidget
///
/// Gets or sets the IconColor of the OpenHAB widget
///
- public int IconColor { get; set; }
+ public string IconColor { get; set; }
///
/// Gets or sets the LabelColor of the OpenHAB widget
///
- public int LabelColor { get; set; }
+ public string LabelColor { get; set; }
///
/// Gets or sets the ValueColor of the OpenHAB widget
///
- public int ValueColor { get; set; }
+ public string ValueColor { get; set; }
///
/// Gets or sets the Encoding of the OpenHAB widget
@@ -106,8 +143,27 @@ public class OpenHABWidget
///
/// Gets or sets the Children of the OpenHAB widget
///
+ [JsonProperty(PropertyName = "widgets")]
public ICollection Children { get; set; }
+ ///
+ /// Gets or sets the Mapping of the OpenHAB widget
+ ///
+ public ICollection Mappings { get; set; }
+
+ ///
+ /// Gets or sets the linked page when available
+ ///
+ public OpenHABSitemap LinkedPage { get; set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public OpenHABWidget()
+ {
+ Children = new List();
+ }
+
///
/// Initializes a new instance of the class.
///
diff --git a/Openhab.Core/Model/OpenHABWidgetMapping.cs b/Openhab.Core/Model/OpenHABWidgetMapping.cs
new file mode 100644
index 00000000..d3320f7a
--- /dev/null
+++ b/Openhab.Core/Model/OpenHABWidgetMapping.cs
@@ -0,0 +1,29 @@
+namespace OpenHAB.Core.Model
+{
+ ///
+ /// A mapping for an OpenHAB Widget
+ ///
+ public class OpenHABWidgetMapping
+ {
+ ///
+ /// Gets or sets the Command of the mapping
+ ///
+ public string Command { get; set; }
+
+ ///
+ /// Gets or sets the Label of the mapping
+ ///
+ public string Label { get; set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// A command
+ /// A label
+ public OpenHABWidgetMapping(string command, string label)
+ {
+ Command = command;
+ Label = label;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Openhab.Core/Model/OpenHabVersion.cs b/Openhab.Core/Model/OpenHabVersion.cs
index 50591786..3ebc325b 100644
--- a/Openhab.Core/Model/OpenHabVersion.cs
+++ b/Openhab.Core/Model/OpenHabVersion.cs
@@ -13,6 +13,11 @@ public enum OpenHABVersion
///
/// OpenHAB V2
///
- Two
+ Two,
+
+ ///
+ /// Used when no connection is available
+ ///
+ None
}
}
diff --git a/Openhab.Core/Model/Settings.cs b/Openhab.Core/Model/Settings.cs
index 758e0150..52ca9b68 100644
--- a/Openhab.Core/Model/Settings.cs
+++ b/Openhab.Core/Model/Settings.cs
@@ -52,7 +52,15 @@ public string OpenHABUrl
return;
}
- _openHABUrl = value;
+ if (value != null && !value.EndsWith("/"))
+ {
+ _openHABUrl = value + "/";
+ }
+ else
+ {
+ _openHABUrl = value;
+ }
+
OnPropertyChanged();
}
}
@@ -74,7 +82,15 @@ public string OpenHABRemoteUrl
return;
}
- _openHABRemoteUrl = value;
+ if (value != null && !value.EndsWith("/"))
+ {
+ _openHABRemoteUrl = value + "/";
+ }
+ else
+ {
+ _openHABRemoteUrl = value;
+ }
+
OnPropertyChanged();
}
}
diff --git a/Openhab.Core/Openhab.Core.csproj b/Openhab.Core/Openhab.Core.csproj
index 077b0e9a..ccfb5f82 100644
--- a/Openhab.Core/Openhab.Core.csproj
+++ b/Openhab.Core/Openhab.Core.csproj
@@ -118,17 +118,22 @@
+
+
+
+
+
@@ -138,6 +143,7 @@
+
diff --git a/Openhab.Core/SDK/IOpenHAB.cs b/Openhab.Core/SDK/IOpenHAB.cs
index 1f5d8483..e271ef6b 100644
--- a/Openhab.Core/SDK/IOpenHAB.cs
+++ b/Openhab.Core/SDK/IOpenHAB.cs
@@ -42,6 +42,7 @@ public interface IOpenHAB
/// Reset the connection to the OpenHAB server after changing the settings in the app
///
/// A representing the asynchronous operation.
- Task ResetConnection();
+ Task ResetConnection();
+
}
}
diff --git a/Openhab.Core/SDK/OpenHAB.cs b/Openhab.Core/SDK/OpenHAB.cs
index 490791d2..b4e79897 100644
--- a/Openhab.Core/SDK/OpenHAB.cs
+++ b/Openhab.Core/SDK/OpenHAB.cs
@@ -6,6 +6,7 @@
using System.Xml.Linq;
using Microsoft.Toolkit.Uwp;
using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
using OpenHAB.Core.Common;
using OpenHAB.Core.Contracts.Services;
using OpenHAB.Core.Model;
@@ -29,11 +30,21 @@ public OpenHAB(ISettingsService settingsService)
}
///
- public async Task ResetConnection()
+ public async Task ResetConnection()
{
var settings = _settingsService.Load();
- await SetValidUrl(settings);
+
+ bool isValid = await SetValidUrl(settings);
+
+ if (!isValid)
+ {
+ return false;
+ }
+
+
OpenHABHttpClient.ResetClient();
+
+ return true;
}
///
@@ -41,8 +52,16 @@ public async Task GetOpenHABVersion()
{
try
{
- var result = await OpenHABHttpClient.Client().GetAsync(Constants.Api.ServerVersion).ConfigureAwait(false);
- return !result.IsSuccessStatusCode ? OpenHABVersion.One : OpenHABVersion.Two;
+ var httpClient = OpenHABHttpClient.Client();
+
+ if (httpClient == null)
+ {
+ return OpenHABVersion.None;
+ }
+
+ var result = await httpClient.GetAsync(Constants.Api.ServerVersion).ConfigureAwait(false);
+ _settingsService.ServerVersion = !result.IsSuccessStatusCode ? OpenHABVersion.One : OpenHABVersion.Two;
+ return _settingsService.ServerVersion;
}
catch (ArgumentNullException ex)
{
@@ -107,7 +126,8 @@ public async Task> LoadItemsFromSitemap(OpenHABSitema
}
// V2 = JSON
- return JsonConvert.DeserializeObject>(resultString);
+ var jsonObject = JObject.Parse(resultString);
+ return JsonConvert.DeserializeObject>(jsonObject["homepage"]["widgets"].ToString());
}
catch (ArgumentNullException ex)
{
@@ -151,42 +171,61 @@ private ICollection ParseWidgets(string resultString)
.ToList();
}
- private async Task SetValidUrl(Settings settings)
+ private async Task SetValidUrl(Settings settings)
{
+ var isRunningInDemoMode = settings.IsRunningInDemoMode != null && settings.IsRunningInDemoMode.Value;
+
+ // no url configured yet
+ if (string.IsNullOrWhiteSpace(settings.OpenHABUrl) && string.IsNullOrWhiteSpace(settings.OpenHABRemoteUrl) && !isRunningInDemoMode)
+ {
+ return false;
+ }
+
+ if (isRunningInDemoMode)
+ {
+ OpenHABHttpClient.BaseUrl = Constants.Api.DemoModeUrl;
+ return true;
+ }
+
+
if (ConnectionHelper.IsInternetOnMeteredConnection)
{
- if (settings.OpenHABRemoteUrl.Trim() == string.Empty)
- {
+ if (settings.OpenHABRemoteUrl.Trim() == string.Empty) {
throw new OpenHABException("No remote url configured");
}
OpenHABHttpClient.BaseUrl = settings.OpenHABRemoteUrl;
+
+
+ return true;
+ }
+
+ bool isReachable = await CheckUrlReachability(settings.OpenHABUrl).ConfigureAwait(false);
+
+ if (isReachable)
+ {
+ OpenHABHttpClient.BaseUrl = settings.OpenHABUrl;
}
else
{
- if (await CheckUrlReachability(settings.OpenHABUrl).ConfigureAwait(false))
- {
- OpenHABHttpClient.BaseUrl = settings.OpenHABUrl;
- }
- else
+ // If remote URL is configured
+ if (!string.IsNullOrWhiteSpace(settings.OpenHABRemoteUrl) && await CheckUrlReachability(settings.OpenHABRemoteUrl).ConfigureAwait(false))
{
- // If remote URL is configured
- if (settings.OpenHABRemoteUrl.Trim() != string.Empty)
- {
- OpenHABHttpClient.BaseUrl = settings.OpenHABRemoteUrl;
- }
- else
- {
- throw new OpenHABException("No valid url configured");
- }
+ OpenHABHttpClient.BaseUrl = settings.OpenHABRemoteUrl;
+ return true;
}
-
- OpenHABHttpClient.BaseUrl = settings.OpenHABUrl;
}
+
+ return false;
}
private async Task CheckUrlReachability(string openHABUrl)
{
+ if (string.IsNullOrWhiteSpace(openHABUrl))
+ {
+ return false;
+ }
+
if (!openHABUrl.EndsWith("/"))
{
openHABUrl = openHABUrl + "/";
@@ -194,16 +233,20 @@ private async Task CheckUrlReachability(string openHABUrl)
try
{
- var client = new HttpClient();
+ var client = OpenHABHttpClient.DisposableClient();
var result = await client.GetAsync(openHABUrl + "rest").ConfigureAwait(false);
- result.EnsureSuccessStatusCode();
- return true;
+ if (result.IsSuccessStatusCode)
+ {
+ return true;
+ }
}
- catch (Exception)
+ catch (InvalidOperationException)
{
return false;
}
+
+ return false;
}
}
}
\ No newline at end of file
diff --git a/Openhab.Core/Services/SettingsService.cs b/Openhab.Core/Services/SettingsService.cs
index 59b74e9e..fd3c8dca 100644
--- a/Openhab.Core/Services/SettingsService.cs
+++ b/Openhab.Core/Services/SettingsService.cs
@@ -13,6 +13,9 @@ public class SettingsService : ISettingsService
{
private ApplicationDataContainer _settingsContainer;
+ ///
+ public OpenHABVersion ServerVersion { get; set; }
+
///
public void Save(Settings settings)
{
diff --git a/Openhab.Core/Services/WidgetNavigationService.cs b/Openhab.Core/Services/WidgetNavigationService.cs
new file mode 100644
index 00000000..f41e74fc
--- /dev/null
+++ b/Openhab.Core/Services/WidgetNavigationService.cs
@@ -0,0 +1,49 @@
+using System.Collections.Generic;
+using System.Linq;
+using OpenHAB.Core.Model;
+
+namespace OpenHAB.Core.Services
+{
+ ///
+ /// Service that keeps track of navigation between linkedpages
+ ///
+ public static class WidgetNavigationService
+ {
+ private static readonly IList WidgetBackStack = new List();
+ private static OpenHABWidget _currentWidget;
+
+ ///
+ /// Gets a value indicating whether there is a previous widget on the backstack
+ ///
+ public static bool CanGoBack => _currentWidget != null;
+
+ ///
+ /// Navigates the backstack to the passed in target
+ ///
+ /// The openHAB widget to navigate to
+ public static void Navigate(OpenHABWidget target)
+ {
+ if (target == _currentWidget)
+ {
+ return;
+ }
+
+ WidgetBackStack.Add(_currentWidget);
+ _currentWidget = target;
+ }
+
+ ///
+ /// Go back to the previous openHAB widget
+ ///
+ /// The previous visted widget
+ public static OpenHABWidget GoBack()
+ {
+ OpenHABWidget backStackEntry = WidgetBackStack.LastOrDefault();
+ WidgetBackStack.Remove(backStackEntry);
+
+ _currentWidget = WidgetBackStack.Count == 0 ? null : backStackEntry;
+
+ return backStackEntry;
+ }
+ }
+}
diff --git a/Openhab.Core/ViewModel/MainViewModel.cs b/Openhab.Core/ViewModel/MainViewModel.cs
index 48e255c2..f1d097fc 100644
--- a/Openhab.Core/ViewModel/MainViewModel.cs
+++ b/Openhab.Core/ViewModel/MainViewModel.cs
@@ -1,9 +1,12 @@
-using System.Collections.ObjectModel;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
using System.Threading.Tasks;
using GalaSoft.MvvmLight;
using OpenHAB.Core.Messages;
using OpenHAB.Core.Model;
using OpenHAB.Core.SDK;
+using OpenHAB.Core.Services;
namespace OpenHAB.Core.ViewModel
{
@@ -16,6 +19,8 @@ public class MainViewModel : ViewModelBase
private ObservableCollection _sitemaps;
private OpenHABSitemap _selectedSitemap;
private OpenHABVersion _version;
+ private ObservableCollection _currentWidgets;
+ private OpenHABWidget _selectedWidget;
///
/// Gets or sets a collection of OpenHAB sitemaps
@@ -46,24 +51,50 @@ public OpenHABSitemap SelectedSitemap
LoadWidgets();
#pragma warning restore 4014
}
+ else
+ { SetWidgetsOnScreen(SelectedSitemap.Widgets);
+ }
}
}
}
+ ///
+ /// Gets or sets the widgets currently on screen
+ ///
+ public ObservableCollection CurrentWidgets
+ {
+ get { return _currentWidgets; } set { Set(ref _currentWidgets, value); }
+ }
+
+ ///
+ /// Gets or sets the selected widget
+ ///
+ public OpenHABWidget SelectedWidget
+ {
+ get { return _selectedWidget; }
+ set { Set(ref _selectedWidget, value); }
+ }
+
///
/// Initializes a new instance of the class.
///
/// The OpenHAB SDK object
public MainViewModel(IOpenHAB openHabsdk)
{
+ CurrentWidgets = new ObservableCollection();
_openHabsdk = openHabsdk;
MessengerInstance.Register(this, async msg =>
{
- await _openHabsdk.ResetConnection();
- await LoadData();
+
+ if (await _openHabsdk.ResetConnection())
+ {
+ await LoadData();
+ }
});
+
MessengerInstance.Register(this, async msg => await TriggerCommand(msg));
+ MessengerInstance.Register(this, msg => OnWidgetClicked(msg.Widget));
#pragma warning disable 4014
LoadData();
#pragma warning restore 4014
@@ -78,13 +109,52 @@ private async Task LoadData()
{
await _openHabsdk.ResetConnection();
_version = await _openHabsdk.GetOpenHABVersion();
+
+ if (_version == OpenHABVersion.None)
+ {
+ return;
+ }
+
var sitemaps = await _openHabsdk.LoadSiteMaps(_version);
Sitemaps = new ObservableCollection(sitemaps);
}
private async Task LoadWidgets()
{
+ if (SelectedSitemap == null)
+ {
+ return;
+ }
+
SelectedSitemap.Widgets = await _openHabsdk.LoadItemsFromSitemap(SelectedSitemap, _version);
+ SetWidgetsOnScreen(SelectedSitemap.Widgets);
+ }
+
+ private void OnWidgetClicked(OpenHABWidget widget)
+ {
+ SelectedWidget = widget;
+ if (SelectedWidget.LinkedPage == null || !SelectedWidget.LinkedPage.Widgets.Any())
+ {
+ return;
+ }
+
+ WidgetNavigationService.Navigate(SelectedWidget);
+ SetWidgetsOnScreen(SelectedWidget?.LinkedPage?.Widgets);
+ }
+
+ ///
+ /// Navigate backwards between linkedpages
+ ///
+ public void WidgetGoBack()
+ {
+ OpenHABWidget widget = WidgetNavigationService.GoBack();
+ SetWidgetsOnScreen(widget != null ? widget.LinkedPage.Widgets : SelectedSitemap.Widgets);
+ }
+
+ private void SetWidgetsOnScreen(ICollection widgets)
+ {
+ CurrentWidgets.Clear();
+ CurrentWidgets.AddRange(widgets);
}
}
}
\ No newline at end of file
diff --git a/Openhab.Core/ViewModel/SettingsViewModel.cs b/Openhab.Core/ViewModel/SettingsViewModel.cs
index 5d580d09..779c9d67 100644
--- a/Openhab.Core/ViewModel/SettingsViewModel.cs
+++ b/Openhab.Core/ViewModel/SettingsViewModel.cs
@@ -1,4 +1,7 @@
-using GalaSoft.MvvmLight;
+using System.Windows.Input;
+using GalaSoft.MvvmLight;
+using GalaSoft.MvvmLight.Command;
+
using GalaSoft.MvvmLight.Views;
using OpenHAB.Core.Contracts.Services;
using OpenHAB.Core.Messages;
@@ -14,6 +17,9 @@ public class SettingsViewModel : ViewModelBase
private readonly ISettingsService _settingsService;
private readonly INavigationService _navigationService;
private Settings _settings;
+ private ICommand _saveCommand;
+
+ public ICommand SaveCommand => _saveCommand ?? (_saveCommand = new RelayCommand(PersistSettings));
///
/// Gets or sets the current user-defined settings