diff --git a/Unigram/Unigram/Common/CameraRotationHelper.cs b/Unigram/Unigram/Common/CameraRotationHelper.cs
new file mode 100644
index 0000000000..54e55f38ab
--- /dev/null
+++ b/Unigram/Unigram/Common/CameraRotationHelper.cs
@@ -0,0 +1,266 @@
+using System;
+using Windows.Devices.Enumeration;
+using Windows.Devices.Sensors;
+using Windows.Graphics.Display;
+using Windows.Media.Capture;
+using Windows.Storage.FileProperties;
+
+namespace Unigram.Common
+{
+ ///
+ /// https://github.com/Microsoft/Windows-universal-samples/blob/master/Samples/CameraStarterKit/cs/CameraRotationHelper.cs
+ ///
+ class CameraRotationHelper
+ {
+ private EnclosureLocation _cameraEnclosureLocation;
+ private DisplayInformation _displayInformation = DisplayInformation.GetForCurrentView();
+ private SimpleOrientationSensor _orientationSensor = SimpleOrientationSensor.GetDefault();
+
+ ///
+ /// Occurs each time the simple orientation sensor reports a new sensor reading or when the display's current or native orientation changes
+ ///
+ public event EventHandler OrientationChanged;
+
+ public CameraRotationHelper(EnclosureLocation cameraEnclosureLocation)
+ {
+ _cameraEnclosureLocation = cameraEnclosureLocation;
+ if (!IsEnclosureLocationExternal(_cameraEnclosureLocation) && _orientationSensor != null)
+ {
+ _orientationSensor.OrientationChanged += SimpleOrientationSensor_OrientationChanged;
+ }
+ _displayInformation.OrientationChanged += DisplayInformation_OrientationChanged;
+ }
+
+ ///
+ /// Detects whether or not the camera is external to the device
+ ///
+ public static bool IsEnclosureLocationExternal(EnclosureLocation enclosureLocation)
+ {
+ return (enclosureLocation == null || enclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Unknown);
+ }
+
+ ///
+ /// Gets the rotation to rotate ui elements
+ ///
+ public SimpleOrientation GetUIOrientation()
+ {
+ if (IsEnclosureLocationExternal(_cameraEnclosureLocation))
+ {
+ // Cameras that are not attached to the device do not rotate along with it, so apply no rotation
+ return SimpleOrientation.NotRotated;
+ }
+
+ // Return the difference between the orientation of the device and the orientation of the app display
+ var deviceOrientation = _orientationSensor?.GetCurrentOrientation() ?? SimpleOrientation.NotRotated;
+ var displayOrientation = ConvertDisplayOrientationToSimpleOrientation(_displayInformation.CurrentOrientation);
+ return SubtractOrientations(displayOrientation, deviceOrientation);
+ }
+
+ ///
+ /// Gets the rotation of the camera to rotate pictures/videos when saving to file
+ ///
+ public SimpleOrientation GetCameraCaptureOrientation()
+ {
+ if (IsEnclosureLocationExternal(_cameraEnclosureLocation))
+ {
+ // Cameras that are not attached to the device do not rotate along with it, so apply no rotation
+ return SimpleOrientation.NotRotated;
+ }
+
+ // Get the device orientation offset by the camera hardware offset
+ var deviceOrientation = _orientationSensor?.GetCurrentOrientation() ?? SimpleOrientation.NotRotated;
+ var result = SubtractOrientations(deviceOrientation, GetCameraOrientationRelativeToNativeOrientation());
+
+ // If the preview is being mirrored for a front-facing camera, then the rotation should be inverted
+ if (ShouldMirrorPreview())
+ {
+ result = MirrorOrientation(result);
+ }
+ return result;
+ }
+
+ ///
+ /// Gets the rotation of the camera to display the camera preview
+ ///
+ public SimpleOrientation GetCameraPreviewOrientation()
+ {
+ if (IsEnclosureLocationExternal(_cameraEnclosureLocation))
+ {
+ // Cameras that are not attached to the device do not rotate along with it, so apply no rotation
+ return SimpleOrientation.NotRotated;
+ }
+
+ // Get the app display rotation offset by the camera hardware offset
+ var result = ConvertDisplayOrientationToSimpleOrientation(_displayInformation.CurrentOrientation);
+ result = SubtractOrientations(result, GetCameraOrientationRelativeToNativeOrientation());
+
+ // If the preview is being mirrored for a front-facing camera, then the rotation should be inverted
+ if (ShouldMirrorPreview())
+ {
+ result = MirrorOrientation(result);
+ }
+ return result;
+ }
+
+ public static PhotoOrientation ConvertSimpleOrientationToPhotoOrientation(SimpleOrientation orientation)
+ {
+ switch (orientation)
+ {
+ case SimpleOrientation.Rotated90DegreesCounterclockwise:
+ return PhotoOrientation.Rotate90;
+ case SimpleOrientation.Rotated180DegreesCounterclockwise:
+ return PhotoOrientation.Rotate180;
+ case SimpleOrientation.Rotated270DegreesCounterclockwise:
+ return PhotoOrientation.Rotate270;
+ case SimpleOrientation.NotRotated:
+ default:
+ return PhotoOrientation.Normal;
+ }
+ }
+
+ public static int ConvertSimpleOrientationToClockwiseDegrees(SimpleOrientation orientation)
+ {
+ switch (orientation)
+ {
+ case SimpleOrientation.Rotated90DegreesCounterclockwise:
+ return 270;
+ case SimpleOrientation.Rotated180DegreesCounterclockwise:
+ return 180;
+ case SimpleOrientation.Rotated270DegreesCounterclockwise:
+ return 90;
+ case SimpleOrientation.NotRotated:
+ default:
+ return 0;
+ }
+ }
+
+ private SimpleOrientation ConvertDisplayOrientationToSimpleOrientation(DisplayOrientations orientation)
+ {
+ SimpleOrientation result;
+ switch (orientation)
+ {
+ case DisplayOrientations.Landscape:
+ result = SimpleOrientation.NotRotated;
+ break;
+ case DisplayOrientations.PortraitFlipped:
+ result = SimpleOrientation.Rotated90DegreesCounterclockwise;
+ break;
+ case DisplayOrientations.LandscapeFlipped:
+ result = SimpleOrientation.Rotated180DegreesCounterclockwise;
+ break;
+ case DisplayOrientations.Portrait:
+ default:
+ result = SimpleOrientation.Rotated270DegreesCounterclockwise;
+ break;
+ }
+
+ // Above assumes landscape; offset is needed if native orientation is portrait
+ if (_displayInformation.NativeOrientation == DisplayOrientations.Portrait)
+ {
+ result = AddOrientations(result, SimpleOrientation.Rotated90DegreesCounterclockwise);
+ }
+
+ return result;
+ }
+
+ private static SimpleOrientation MirrorOrientation(SimpleOrientation orientation)
+ {
+ // This only affects the 90 and 270 degree cases, because rotating 0 and 180 degrees is the same clockwise and counter-clockwise
+ switch (orientation)
+ {
+ case SimpleOrientation.Rotated90DegreesCounterclockwise:
+ return SimpleOrientation.Rotated270DegreesCounterclockwise;
+ case SimpleOrientation.Rotated270DegreesCounterclockwise:
+ return SimpleOrientation.Rotated90DegreesCounterclockwise;
+ }
+ return orientation;
+ }
+
+ private static SimpleOrientation AddOrientations(SimpleOrientation a, SimpleOrientation b)
+ {
+ var aRot = ConvertSimpleOrientationToClockwiseDegrees(a);
+ var bRot = ConvertSimpleOrientationToClockwiseDegrees(b);
+ var result = (aRot + bRot) % 360;
+ return ConvertClockwiseDegreesToSimpleOrientation(result);
+ }
+
+ private static SimpleOrientation SubtractOrientations(SimpleOrientation a, SimpleOrientation b)
+ {
+ var aRot = ConvertSimpleOrientationToClockwiseDegrees(a);
+ var bRot = ConvertSimpleOrientationToClockwiseDegrees(b);
+ // Add 360 to ensure the modulus operator does not operate on a negative
+ var result = (360 + (aRot - bRot)) % 360;
+ return ConvertClockwiseDegreesToSimpleOrientation(result);
+ }
+
+ private static VideoRotation ConvertSimpleOrientationToVideoRotation(SimpleOrientation orientation)
+ {
+ switch (orientation)
+ {
+ case SimpleOrientation.Rotated90DegreesCounterclockwise:
+ return VideoRotation.Clockwise270Degrees;
+ case SimpleOrientation.Rotated180DegreesCounterclockwise:
+ return VideoRotation.Clockwise180Degrees;
+ case SimpleOrientation.Rotated270DegreesCounterclockwise:
+ return VideoRotation.Clockwise90Degrees;
+ case SimpleOrientation.NotRotated:
+ default:
+ return VideoRotation.None;
+ }
+ }
+
+ private static SimpleOrientation ConvertClockwiseDegreesToSimpleOrientation(int orientation)
+ {
+ switch (orientation)
+ {
+ case 270:
+ return SimpleOrientation.Rotated90DegreesCounterclockwise;
+ case 180:
+ return SimpleOrientation.Rotated180DegreesCounterclockwise;
+ case 90:
+ return SimpleOrientation.Rotated270DegreesCounterclockwise;
+ case 0:
+ default:
+ return SimpleOrientation.NotRotated;
+ }
+ }
+
+ private void SimpleOrientationSensor_OrientationChanged(SimpleOrientationSensor sender, SimpleOrientationSensorOrientationChangedEventArgs args)
+ {
+ if (args.Orientation != SimpleOrientation.Faceup && args.Orientation != SimpleOrientation.Facedown)
+ {
+ // Only raise the OrientationChanged event if the device is not parallel to the ground. This allows users to take pictures of documents (FaceUp)
+ // or the ceiling (FaceDown) in portrait or landscape, by first holding the device in the desired orientation, and then pointing the camera
+ // either up or down, at the desired subject.
+ //Note: This assumes that the camera is either facing the same way as the screen, or the opposite way. For devices with cameras mounted
+ // on other panels, this logic should be adjusted.
+ OrientationChanged?.Invoke(this, false);
+ }
+ }
+
+ private void DisplayInformation_OrientationChanged(DisplayInformation sender, object args)
+ {
+ OrientationChanged?.Invoke(this, true);
+ }
+
+ private bool ShouldMirrorPreview()
+ {
+ // It is recommended that applications mirror the preview for front-facing cameras, as it gives users a more natural experience, since it behaves more like a mirror
+ return (_cameraEnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Front);
+ }
+
+ private SimpleOrientation GetCameraOrientationRelativeToNativeOrientation()
+ {
+ // Get the rotation angle of the camera enclosure as it is mounted in the device hardware
+ var enclosureAngle = ConvertClockwiseDegreesToSimpleOrientation((int)_cameraEnclosureLocation.RotationAngleInDegreesClockwise);
+
+ // Account for the fact that, on portrait-first devices, the built in camera sensor is read at a 90 degree offset to the native orientation
+ if (_displayInformation.NativeOrientation == DisplayOrientations.Portrait && !IsEnclosureLocationExternal(_cameraEnclosureLocation))
+ {
+ enclosureAngle = AddOrientations(SimpleOrientation.Rotated90DegreesCounterclockwise, enclosureAngle);
+ }
+
+ return enclosureAngle;
+ }
+ }
+}
diff --git a/Unigram/Unigram/Controls/DialogBackgroundPresenter.cs b/Unigram/Unigram/Controls/DialogBackgroundPresenter.cs
index 31b92edb13..c662ccdbde 100644
--- a/Unigram/Unigram/Controls/DialogBackgroundPresenter.cs
+++ b/Unigram/Unigram/Controls/DialogBackgroundPresenter.cs
@@ -18,7 +18,7 @@ namespace Unigram.Controls
public class DialogBackgroundPresenter : ContentControl, IHandle
{
private DialogBackground _defaultBackground;
- private Image _imageBackground;
+ private Rectangle _imageBackground;
private Rectangle _colorBackground;
public DialogBackgroundPresenter()
@@ -48,13 +48,13 @@ private async void Reload()
if (item is StorageFile file)
{
if (_imageBackground == null)
- _imageBackground = new Image { Stretch = Stretch.UniformToFill };
+ _imageBackground = new Rectangle();
using (var stream = await file.OpenReadAsync())
{
var bitmap = new BitmapImage();
await bitmap.SetSourceAsync(stream);
- _imageBackground.Source = bitmap;
+ _imageBackground.Fill = new ImageBrush { ImageSource = bitmap, AlignmentX = AlignmentX.Center, AlignmentY = AlignmentY.Center, Stretch = Stretch.UniformToFill };
}
Content = _imageBackground;
diff --git a/Unigram/Unigram/Controls/Views/RoundVideoView.xaml b/Unigram/Unigram/Controls/Views/RoundVideoView.xaml
index 4d387f213b..875cd1d920 100644
--- a/Unigram/Unigram/Controls/Views/RoundVideoView.xaml
+++ b/Unigram/Unigram/Controls/Views/RoundVideoView.xaml
@@ -65,8 +65,8 @@
-
-
+
+
diff --git a/Unigram/Unigram/Controls/Views/RoundVideoView.xaml.cs b/Unigram/Unigram/Controls/Views/RoundVideoView.xaml.cs
index c88bbf22d6..ce041015d3 100644
--- a/Unigram/Unigram/Controls/Views/RoundVideoView.xaml.cs
+++ b/Unigram/Unigram/Controls/Views/RoundVideoView.xaml.cs
@@ -70,42 +70,42 @@ public IAsyncAction SetAsync(MediaCapture media)
{
return Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
{
- var profile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Vga);
- profile.Audio = null;
- profile.Container = null;
+ //var profile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Vga);
+ //profile.Audio = null;
+ //profile.Container = null;
- _preview = MediaCapturePreviewSource.CreateFromVideoEncodingProperties(profile.Video);
- await media.StartPreviewToCustomSinkAsync(profile, _preview.MediaSink);
+ //_preview = MediaCapturePreviewSource.CreateFromVideoEncodingProperties(profile.Video);
+ //await media.StartPreviewToCustomSinkAsync(profile, _preview.MediaSink);
- _player = new MediaPlayer();
- _player.RealTimePlayback = true;
- _player.AutoPlay = true;
- _player.Source = _preview.MediaSource as IMediaPlaybackSource;
+ //_player = new MediaPlayer();
+ //_player.RealTimePlayback = true;
+ //_player.AutoPlay = true;
+ //_player.Source = _preview.MediaSource as IMediaPlaybackSource;
- _surface = _player.GetSurface(_compositor);
+ //_surface = _player.GetSurface(_compositor);
- var brush = _compositor.CreateSurfaceBrush(_surface.CompositionSurface);
- brush.Stretch = CompositionStretch.UniformToFill;
+ //var brush = _compositor.CreateSurfaceBrush(_surface.CompositionSurface);
+ //brush.Stretch = CompositionStretch.UniformToFill;
- var mask = ImageLoader.Instance.LoadCircle(200, Colors.White).Brush;
- var graphicsEffect = new AlphaMaskEffect
- {
- Source = new CompositionEffectSourceParameter("image"),
- AlphaMask = new CompositionEffectSourceParameter("mask")
- };
+ //var mask = ImageLoader.Instance.LoadCircle(200, Colors.White).Brush;
+ //var graphicsEffect = new AlphaMaskEffect
+ //{
+ // Source = new CompositionEffectSourceParameter("image"),
+ // AlphaMask = new CompositionEffectSourceParameter("mask")
+ //};
- var effectFactory = _compositor.CreateEffectFactory(graphicsEffect);
- var effectBrush = effectFactory.CreateBrush();
- effectBrush.SetSourceParameter("image", brush);
- effectBrush.SetSourceParameter("mask", mask);
+ //var effectFactory = _compositor.CreateEffectFactory(graphicsEffect);
+ //var effectBrush = effectFactory.CreateBrush();
+ //effectBrush.SetSourceParameter("image", brush);
+ //effectBrush.SetSourceParameter("mask", mask);
- _capture.Brush = effectBrush;
+ //_capture.Brush = effectBrush;
- //Capture.Source = media;
- //await media.StartPreviewAsync();
+ Capture.Source = media;
+ await media.StartPreviewAsync();
});
}
}
diff --git a/Unigram/Unigram/Controls/VoiceButton.cs b/Unigram/Unigram/Controls/VoiceButton.cs
index 9b184a9baf..08b0d5111f 100644
--- a/Unigram/Unigram/Controls/VoiceButton.cs
+++ b/Unigram/Unigram/Controls/VoiceButton.cs
@@ -181,7 +181,9 @@ private void Start()
{
_recorder.m_mediaCapture = new MediaCapture();
- _recorder.settings.VideoDeviceId = await _recorder.GetVideoProfileSupportedDeviceIdAsync(Windows.Devices.Enumeration.Panel.Front);
+ var cameraDevice = await _recorder.FindCameraDeviceByPanelAsync(Windows.Devices.Enumeration.Panel.Front);
+
+ _recorder.settings.VideoDeviceId = cameraDevice.Id;
await _recorder.m_mediaCapture.InitializeAsync(_recorder.settings);
if (_video)
@@ -355,21 +357,16 @@ private void InitializeSettings()
settings.StreamingCaptureMode = m_isVideo ? StreamingCaptureMode.AudioAndVideo : StreamingCaptureMode.Audio;
}
- public async Task GetVideoProfileSupportedDeviceIdAsync(Windows.Devices.Enumeration.Panel panel)
+ public async Task FindCameraDeviceByPanelAsync(Windows.Devices.Enumeration.Panel desiredPanel)
{
- var deviceId = string.Empty;
- var devices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
+ // Get available devices for capturing pictures
+ var allVideoDevices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
- foreach (var device in devices)
- {
- if (MediaCapture.IsVideoProfileSupported(device.Id) && device.EnclosureLocation.Panel == panel)
- {
- deviceId = device.Id;
- break;
- }
- }
+ // Get the desired camera by panel
+ DeviceInformation desiredDevice = allVideoDevices.FirstOrDefault(x => x.EnclosureLocation != null && x.EnclosureLocation.Panel == desiredPanel);
- return deviceId;
+ // If there is no device mounted on the desired panel, return the first device found
+ return desiredDevice ?? allVideoDevices.FirstOrDefault();
}
public async Task StartAsync()
diff --git a/Unigram/Unigram/Unigram.csproj b/Unigram/Unigram/Unigram.csproj
index 75e0f677d5..0fe0620a4a 100644
--- a/Unigram/Unigram/Unigram.csproj
+++ b/Unigram/Unigram/Unigram.csproj
@@ -97,6 +97,7 @@
+
diff --git a/Unigram/Unigram/ViewModels/Settings/SettingsWallpaperViewModel.cs b/Unigram/Unigram/ViewModels/Settings/SettingsWallpaperViewModel.cs
index e42809155e..ab9d88df7f 100644
--- a/Unigram/Unigram/ViewModels/Settings/SettingsWallpaperViewModel.cs
+++ b/Unigram/Unigram/ViewModels/Settings/SettingsWallpaperViewModel.cs
@@ -13,6 +13,7 @@
using Unigram.Core.Common;
using Windows.Storage;
using Windows.Storage.Pickers;
+using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;
namespace Unigram.ViewModels.Settings
@@ -43,7 +44,7 @@ public override Task OnNavigatedToAsync(object parameter, NavigationMode mode, I
return base.OnNavigatedToAsync(parameter, mode, state);
}
- private void UpdateView()
+ private async void UpdateView()
{
if (Items == null)
{
@@ -55,6 +56,17 @@ private void UpdateView()
{
IsLocal = true;
SelectedItem = null;
+
+ var item = await ApplicationData.Current.LocalFolder.TryGetItemAsync(FileUtils.GetTempFilePath("wallpaper.jpg"));
+ if (item is StorageFile file)
+ {
+ using (var stream = await file.OpenReadAsync())
+ {
+ var bitmap = new BitmapImage();
+ await bitmap.SetSourceAsync(stream);
+ Local = bitmap;
+ }
+ }
}
else
{
@@ -75,6 +87,19 @@ public bool IsLocal
}
}
+ private BitmapImage _local;
+ public BitmapImage Local
+ {
+ get
+ {
+ return _local;
+ }
+ set
+ {
+ Set(ref _local, value);
+ }
+ }
+
private TLWallPaperBase _selectedItem;
public TLWallPaperBase SelectedItem
{
@@ -88,6 +113,7 @@ public TLWallPaperBase SelectedItem
if (value != null)
{
+ Local = null;
IsLocal = false;
}
}
@@ -111,6 +137,13 @@ private async void LocalExecute()
IsLocal = true;
SelectedItem = null;
+
+ using (var stream = await result.OpenReadAsync())
+ {
+ var bitmap = new BitmapImage();
+ await bitmap.SetSourceAsync(stream);
+ Local = bitmap;
+ }
}
}
diff --git a/Unigram/Unigram/Views/Settings/SettingsWallpaperPage.xaml b/Unigram/Unigram/Views/Settings/SettingsWallpaperPage.xaml
index 7bf66d535a..c28dcc18f6 100644
--- a/Unigram/Unigram/Views/Settings/SettingsWallpaperPage.xaml
+++ b/Unigram/Unigram/Views/Settings/SettingsWallpaperPage.xaml
@@ -30,6 +30,12 @@
Command="{x:Bind ViewModel.DoneCommand}"
Canvas.ZIndex="1"/>
+
+
+
+
+
+