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 @@ + + + + + + + + + + + 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 @@  - - - - - - - - - + + + + + + + + + - + - - - - + + + + + + + + + + + + + + + + + +