From 21119facf36081da4472ede4c187f31693eb411d Mon Sep 17 00:00:00 2001 From: Patrick Kranz <patrick-kranz@live.de> Date: Sun, 9 May 2021 14:44:53 +0200 Subject: [PATCH 1/2] Added DeviceSettingsPage with QR reader --- Signal-Windows/Controls/QRScanner.cs | 366 ++++++++++++++++++ Signal-Windows/Controls/QRScanner.xaml | 34 ++ Signal-Windows/Package.appxmanifest | 2 + Signal-Windows/Signal-Windows.csproj | 15 + .../ViewModels/DeviceSettingsPageViewmodel.cs | 124 ++++++ Signal-Windows/ViewModels/ViewModelLocator.cs | 6 + Signal-Windows/Views/DeviceSettingsPage.xaml | 40 ++ .../Views/DeviceSettingsPage.xaml.cs | 96 +++++ Signal-Windows/Views/GlobalSettingsPage.xaml | 6 + .../Views/GlobalSettingsPage.xaml.cs | 5 + 10 files changed, 694 insertions(+) create mode 100644 Signal-Windows/Controls/QRScanner.cs create mode 100644 Signal-Windows/Controls/QRScanner.xaml create mode 100644 Signal-Windows/ViewModels/DeviceSettingsPageViewmodel.cs create mode 100644 Signal-Windows/Views/DeviceSettingsPage.xaml create mode 100644 Signal-Windows/Views/DeviceSettingsPage.xaml.cs diff --git a/Signal-Windows/Controls/QRScanner.cs b/Signal-Windows/Controls/QRScanner.cs new file mode 100644 index 0000000..4d362c1 --- /dev/null +++ b/Signal-Windows/Controls/QRScanner.cs @@ -0,0 +1,366 @@ +using System; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Media; + +using System.Threading; +using Windows.Media.Capture; +using System.Threading.Tasks; +using Windows.Media; +using Windows.Media.MediaProperties; +using Windows.Graphics.Imaging; +using Windows.Storage.Streams; +using Windows.Media.Devices; +using Windows.Devices.Enumeration; +using ZXing; +using libsignalservice; +using Microsoft.Extensions.Logging; + +namespace Signal_Windows.Controls +{ + + // this Control draw heavaly form the [Barcode_Scanner_UWP](https://github.com/programmersommer/Barcode_Scanner_UWP) sample. + public sealed partial class QRScanner : UserControl, IDisposable + { + + private static readonly ILogger Logger = LibsignalLogging.CreateLogger<QRScanner>(); + + public event Action<string> CodeFound; + public event Action Cancled; + public event Action<Exception> Error; + + private MediaCapture mediaCapture; + private readonly DispatcherTimer timerFocus; + private readonly SemaphoreSlim videoCaptureSemaphore = new SemaphoreSlim(1); + private readonly SemaphoreSlim scanSemaphore = new SemaphoreSlim(1); + private bool timerCaptureInProgress = false; + + private double width = 640; + private double height = 480; + private bool isReady = true; + private bool isInitialized = false; + private bool isScanning = true; + + private BarcodeReader _ZXingReader; + private bool disposedValue; + + public QRScanner() + { + this.InitializeComponent(); + + this.timerFocus = new DispatcherTimer(); + } + + #region capturing photo + + private async Task InitCamera() + { + if (this.isInitialized == true) + return; + + var devices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture); + + var rearCamera = devices.FirstOrDefault(x => x.EnclosureLocation?.Panel == Windows.Devices.Enumeration.Panel.Back); + + try + { + + if (rearCamera != null) + { + await this.mediaCapture.InitializeAsync(new MediaCaptureInitializationSettings { VideoDeviceId = rearCamera.Id }); + } + + this.isInitialized = true; + await this.SetResolution(); + if (this.mediaCapture.VideoDeviceController.FlashControl.Supported) + this.mediaCapture.VideoDeviceController.FlashControl.Auto = false; + } + catch { } + } + + private async Task SetResolution() + { + System.Collections.Generic.IReadOnlyList<IMediaEncodingProperties> res; + res = this.mediaCapture.VideoDeviceController.GetAvailableMediaStreamProperties(MediaStreamType.VideoPreview); + uint maxResolution = 0; + var indexMaxResolution = 0; + + if (res.Count >= 1) + { + for (var i = 0; i < res.Count; i++) + { + var vp = (VideoEncodingProperties)res[i]; + + if (vp.Width > maxResolution) + { + indexMaxResolution = i; + maxResolution = vp.Width; + this.width = vp.Width; + this.height = vp.Height; + } + } + await this.mediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.VideoPreview, res[indexMaxResolution]); + } + } + + + private void Page_SizeChanged(object sender, SizeChangedEventArgs e) + { + this.SetGridSize(); + } + + + private void SetGridSize() + { + this.VideoCaptureElement.Height = this.previewGrid.Height - 100; + this.VideoCaptureElement.Width = this.previewGrid.Width; + } + + #endregion + + + #region Barcode scanner + + private async void cancelButton_Click(object sender, RoutedEventArgs e) + { + await this.Cleanup(); + Cancled?.Invoke(); + } + + + public async Task Cleanup() + { + if (!this.isReady) + { + this.isScanning = false; + this.timerFocus.Stop(); + this.timerFocus.Tick -= this.timerFocus_Tick; + + await this.mediaCapture.StopPreviewAsync(); + this.mediaCapture.FocusChanged -= this.mediaCaptureManager_FocusChanged; + + this.isReady = true; + } + } + + private async Task StartPreview() + { + if (Windows.System.Profile.AnalyticsInfo.VersionInfo.DeviceFamily == "Windows.Mobile") + { + this.mediaCapture.SetPreviewRotation(VideoRotation.Clockwise90Degrees); + this.mediaCapture.SetPreviewMirroring(true); + } + + var focusControl = this.mediaCapture.VideoDeviceController.FocusControl; + if (focusControl.FocusChangedSupported) + { + this.isReady = false; + this.isScanning = true; + + this.mediaCapture.FocusChanged += this.mediaCaptureManager_FocusChanged; + this.VideoCaptureElement.Source = this.mediaCapture; + this.VideoCaptureElement.Stretch = Stretch.UniformToFill; + await this.mediaCapture.StartPreviewAsync(); + await focusControl.UnlockAsync(); + var settings = new FocusSettings { Mode = FocusMode.Continuous, AutoFocusRange = AutoFocusRange.FullRange }; + focusControl.Configure(settings); + await focusControl.FocusAsync(); + } + else if (focusControl.Supported) + { + this.isReady = false; + this.isScanning = true; + + this.VideoCaptureElement.Source = this.mediaCapture; + this.VideoCaptureElement.Stretch = Stretch.UniformToFill; + await this.mediaCapture.StartPreviewAsync(); + await focusControl.UnlockAsync(); + + focusControl.Configure(new FocusSettings { Mode = FocusMode.Auto }); + this.timerFocus.Tick += this.timerFocus_Tick; + this.timerFocus.Interval = new TimeSpan(0, 0, 3); + this.timerFocus.Start(); + } + else + { + await this.OnErrorAsync(new NotSupportedException("AutoFocus control is not supported on this device")); + } + + + } + + private async void mediaCaptureManager_FocusChanged(MediaCapture sender, MediaCaptureFocusChangedEventArgs args) + { + if (this.isScanning) + await this.CapturePhotoFromCameraAsync(); + } + + private async void timerFocus_Tick(object sender, object e) + { + if (this.timerCaptureInProgress) + return; // if camera is still focusing + + if (this.isScanning) + { + this.timerCaptureInProgress = true; + + await this.mediaCapture.VideoDeviceController.FocusControl.FocusAsync(); + await this.CapturePhotoFromCameraAsync(); + + this.timerCaptureInProgress = false; + } + } + + private async Task CapturePhotoFromCameraAsync() + { + if (!this.isScanning) + return; + + if (await this.videoCaptureSemaphore.WaitAsync(0) == true) + { + try + { + var videoFrame = new VideoFrame(BitmapPixelFormat.Bgra8, (int)this.width, (int)this.height); + await this.mediaCapture.GetPreviewFrameAsync(videoFrame); + + var bytes = await this.SaveSoftwareBitmapToBufferAsync(videoFrame.SoftwareBitmap); + await this.ScanImageAsync(bytes); + } + finally + { + this.videoCaptureSemaphore.Release(); + } + } + } + + private async Task<byte[]> SaveSoftwareBitmapToBufferAsync(SoftwareBitmap softwareBitmap) + { + byte[] bytes = null; + + try + { + IRandomAccessStream stream = new InMemoryRandomAccessStream(); + + // Create an encoder with the desired format + var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.BmpEncoderId, stream); + encoder.SetSoftwareBitmap(softwareBitmap); + encoder.IsThumbnailGenerated = false; + await encoder.FlushAsync(); + + bytes = new byte[stream.Size]; + + // This returns IAsyncOperationWithProgess, so you can add additional progress handling + await stream.ReadAsync(bytes.AsBuffer(), (uint)stream.Size, Windows.Storage.Streams.InputStreamOptions.None); + } + + catch (Exception ex) + { + Logger.LogError(ex.Message); + } + + return bytes; + } + + + private async Task BarCodeFound(string barcode) + { + await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => + { + this.timerFocus.Stop(); + this.isScanning = false; + + if (barcode != null) + { + CodeFound?.Invoke(barcode); + } + }); + } + + + private async Task OnErrorAsync(Exception e) + { + await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => this.Error?.Invoke(e)); + + } + + private async Task ScanImageAsync(byte[] pixelsArray) + { + await this.scanSemaphore.WaitAsync(); + try + { + if (this.isScanning) + { + + var result = this._ZXingReader.Decode(pixelsArray, (int)this.width, (int)this.height, RGBLuminanceSource.BitmapFormat.Unknown); + if (result != null) + { + await this.BarCodeFound(result.Text); + } + } + } + catch (Exception e) + { + Logger.LogError(e.Message); + } + finally + { + this.scanSemaphore.Release(); + } + } + + #endregion + + + private async void UserControl_Unloaded(object sender, RoutedEventArgs e) + { + await this.Cleanup(); + } + + + public async Task StartScan() + { + this.btnBarcodeCancel.IsEnabled = false; + this.mediaCapture = new MediaCapture(); + this.isInitialized = false; + this.isScanning = false; + + await this.InitCamera(); + + if (this.isInitialized == false) + return; + + + this._ZXingReader = new BarcodeReader() + { + AutoRotate = true, + Options = new ZXing.Common.DecodingOptions() { TryHarder = false, PossibleFormats = new BarcodeFormat[] { BarcodeFormat.All_1D, BarcodeFormat.QR_CODE } } + }; + + await this.StartPreview(); + this.btnBarcodeCancel.IsEnabled = true; + } + + private void Dispose(bool disposing) + { + if (!this.disposedValue) + { + if (disposing) + { + this.videoCaptureSemaphore.Dispose(); + this.scanSemaphore.Dispose(); + } + + this.disposedValue = true; + } + } + + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + this.Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/Signal-Windows/Controls/QRScanner.xaml b/Signal-Windows/Controls/QRScanner.xaml new file mode 100644 index 0000000..122d65f --- /dev/null +++ b/Signal-Windows/Controls/QRScanner.xaml @@ -0,0 +1,34 @@ +<UserControl + x:Class="Signal_Windows.Controls.QRScanner" + 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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + d:DesignHeight="300" + d:DesignWidth="400" + SizeChanged="Page_SizeChanged" + Unloaded="UserControl_Unloaded" + mc:Ignorable="d"> + + <Grid x:Name="previewGrid"> + <Grid.RowDefinitions> + <RowDefinition Height="*" /> + <RowDefinition Height="100" /> + </Grid.RowDefinitions> + <CaptureElement + x:Name="VideoCaptureElement" + Grid.Row="0" + HorizontalAlignment="Stretch" + VerticalAlignment="Stretch" /> + <StackPanel + Grid.Row="1" + HorizontalAlignment="Center" + Orientation="Horizontal"> + <Button + x:Name="btnBarcodeCancel" + Click="btnBarcodeCancel_Click" + Content="Cancel" /> + </StackPanel> + </Grid> + +</UserControl> diff --git a/Signal-Windows/Package.appxmanifest b/Signal-Windows/Package.appxmanifest index f5a85e9..c2a0599 100644 --- a/Signal-Windows/Package.appxmanifest +++ b/Signal-Windows/Package.appxmanifest @@ -46,6 +46,8 @@ <Capabilities> <Capability Name="internetClient" /> <uap:Capability Name="contacts" /> + <DeviceCapability Name="webcam"/> + <DeviceCapability Name="microphone"/> </Capabilities> <Extensions> <Extension Category="windows.certificates"> diff --git a/Signal-Windows/Signal-Windows.csproj b/Signal-Windows/Signal-Windows.csproj index bceec9c..81d85ce 100644 --- a/Signal-Windows/Signal-Windows.csproj +++ b/Signal-Windows/Signal-Windows.csproj @@ -169,6 +169,9 @@ <Compile Include="Controls\Attachment.xaml.cs"> <DependentUpon>Attachment.xaml</DependentUpon> </Compile> + <Compile Include="Controls\QRScanner.cs"> + <DependentUpon>QRScanner.xaml</DependentUpon> + </Compile> <Compile Include="Controls\IdentityKeyChangeMessage.xaml.cs"> <DependentUpon>IdentityKeyChangeMessage.xaml</DependentUpon> </Compile> @@ -200,6 +203,7 @@ <Compile Include="ViewModels\CaptchaPageViewModel.cs" /> <Compile Include="ViewModels\ChatsAndMediaSettingsPageViewModel.cs" /> <Compile Include="ViewModels\ConversationSettingsPageViewModel.cs" /> + <Compile Include="ViewModels\DeviceSettingsPageViewmodel.cs" /> <Compile Include="ViewModels\FinishRegistrationPageViewModel.cs" /> <Compile Include="ViewModels\GlobalSettingsPageViewModel.cs" /> <Compile Include="ViewModels\LinkPageViewModel.cs" /> @@ -231,6 +235,9 @@ <Compile Include="Views\CaptchaPage.xaml.cs"> <DependentUpon>CaptchaPage.xaml</DependentUpon> </Compile> + <Compile Include="Views\DeviceSettingsPage.xaml.cs"> + <DependentUpon>DeviceSettingsPage.xaml</DependentUpon> + </Compile> <Compile Include="Views\ChatsAndMediaSettingsPage.xaml.cs"> <DependentUpon>ChatsAndMediaSettingsPage.xaml</DependentUpon> </Compile> @@ -298,6 +305,10 @@ <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> </Page> + <Page Include="Controls\QRScanner.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> <Page Include="Controls\IdentityKeyChangeMessage.xaml"> <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> @@ -354,6 +365,10 @@ <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> </Page> + <Page Include="Views\DeviceSettingsPage.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> <Page Include="Views\ChatsAndMediaSettingsPage.xaml"> <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> diff --git a/Signal-Windows/ViewModels/DeviceSettingsPageViewmodel.cs b/Signal-Windows/ViewModels/DeviceSettingsPageViewmodel.cs new file mode 100644 index 0000000..3073867 --- /dev/null +++ b/Signal-Windows/ViewModels/DeviceSettingsPageViewmodel.cs @@ -0,0 +1,124 @@ +using GalaSoft.MvvmLight; +using libsignal; +using libsignal.util; +using libsignalservice; +using libsignalservice.messages.multidevice; +using libsignalservice.util; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Signal_Windows.ViewModels +{ + public class DeviceSettingsPageViewmodel : ViewModelBase + { + private static readonly ILogger Logger = LibsignalLogging.CreateLogger<AdvancedSettingsPageViewModel>(); + + public ReadOnlyObservableCollection<DeviceViewmodel> Devices { get; } + private readonly ObservableCollection<DeviceViewmodel> devices; + + public DeviceSettingsPageViewmodel() + { + this.devices = new ObservableCollection<DeviceViewmodel>(); + this.Devices = new ReadOnlyObservableCollection<DeviceViewmodel>(this.devices); + } + + public async void OnNavigatedTo() + { + await this.RefreshList(); + } + + private async Task RefreshList() + { + this.devices.Clear(); + var devices = await App.Handle.AccountManager.GetDevicesAsync(); + this.devices.AddRange(devices.Select(x => new DeviceViewmodel(x))); + } + + public async Task AddDevice(Uri uri) + { + var toAdd = DeviceProtocoll.FromUri(uri); + + var code = await App.Handle.AccountManager.GetNewDeviceVerificationCodeAsync(); + + // I'm not sure where which parameter goes... + // but it failes when the QR code is to old, so the first two are propably correct... + await App.Handle.AccountManager.AddDeviceAsync(toAdd.Uuid, toAdd.IdentetyKey.getPublicKey(), + new IdentityKeyPair(Base64.Decode(App.Handle.Store.IdentityKeyPair)), + Base64.Decode(App.Handle.Store.SignalingKey), + code); + + + await this.RefreshList(); + } + + } + + public class DeviceProtocoll + { + private DeviceProtocoll(string uuid, IdentityKey identetyKey) + { + this.Uuid = uuid; + this.IdentetyKey = identetyKey; + } + + public string Uuid { get; } + public IdentityKey IdentetyKey { get; } + + public static DeviceProtocoll FromUri(Uri uri) + { + if (uri.Scheme.ToLower() != "tsdevice") + throw new ArgumentException(nameof(uri), $"The protocoll must be tsdevice but was {uri.Scheme}"); + if (uri.Query.Length <= 1) + throw new ArgumentException(nameof(uri), $"The querry is not valid. Quary was: {uri.Query}"); + + var query = uri.Query.Substring(1); + + var parameters = query.Split('&'); + string uuid = null; + string pub_key = null; + + foreach (var item in parameters) + { + if (item.StartsWith("uuid=")) + uuid = item.Substring("uuid=".Length); + else if (item.StartsWith("pub_key=")) + pub_key = item.Substring("pub_key=".Length); + } + + if (pub_key == null || uuid == null) + { + throw new ArgumentException(nameof(uri), + (pub_key == null + ? "The pub_key parameter is missing." + : "") + + (uuid == null + ? "The uuid parameter is missing." + : "") + ); + + } + + var publicKeyBytes = Base64.Decode(Uri.UnescapeDataString(pub_key)); + var identetyKey = new IdentityKey(publicKeyBytes, 0); + return new DeviceProtocoll(uuid, identetyKey); + } + } + + + public class DeviceViewmodel : ViewModelBase + { + + public DeviceViewmodel(DeviceInfo device) + { + this.Name = device.Name; + } + + public string Name { get; } + } +} diff --git a/Signal-Windows/ViewModels/ViewModelLocator.cs b/Signal-Windows/ViewModels/ViewModelLocator.cs index a7a9fce..96445fe 100644 --- a/Signal-Windows/ViewModels/ViewModelLocator.cs +++ b/Signal-Windows/ViewModels/ViewModelLocator.cs @@ -46,6 +46,7 @@ public ViewModelLocator() SimpleIoc.Default.Register<AppearanceSettingsPageViewModel>(); SimpleIoc.Default.Register<ChatsAndMediaSettingsPageViewModel>(); SimpleIoc.Default.Register<AdvancedSettingsPageViewModel>(); + SimpleIoc.Default.Register<DeviceSettingsPageViewmodel>(); SimpleIoc.Default.Register<BlockedContactsPageViewModel>(); SimpleIoc.Default.Register<CaptchaPageViewModel>(); } @@ -144,6 +145,11 @@ public AdvancedSettingsPageViewModel AdvancedSettingsPageInstance get { return ServiceLocator.Current.GetInstance<AdvancedSettingsPageViewModel>(Key.ToString()); } } + public DeviceSettingsPageViewmodel DeviceSettingsPageInstance + { + get { return ServiceLocator.Current.GetInstance<DeviceSettingsPageViewmodel>(Key.ToString()); } + } + public BlockedContactsPageViewModel BlockedContactsPageInstance { get { return ServiceLocator.Current.GetInstance<BlockedContactsPageViewModel>(Key.ToString()); } diff --git a/Signal-Windows/Views/DeviceSettingsPage.xaml b/Signal-Windows/Views/DeviceSettingsPage.xaml new file mode 100644 index 0000000..813fadb --- /dev/null +++ b/Signal-Windows/Views/DeviceSettingsPage.xaml @@ -0,0 +1,40 @@ +<Page + x:Class="Signal_Windows.Views.DeviceSettingsPage" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:controls="using:Signal_Windows.Controls" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:local="using:Signal_Windows.Views" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" + DataContext="{Binding DeviceSettingsPageInstance, Source={StaticResource Locator}}" + mc:Ignorable="d"> + + <Grid x:Name="root" SizeChanged="root_SizeChanged"> + <Grid.RowDefinitions> + <RowDefinition Height="Auto" /> + <RowDefinition /> + </Grid.RowDefinitions> + <Popup + x:Name="ScannerPopup" + Grid.RowSpan="2" + IsLightDismissEnabled="False" + IsOpen="False"> + <Grid> + <controls:QRScanner x:Name="scanner" CodeFound="CodeFound" Cancled="scanner_Cancled" /> + </Grid> + </Popup> + + + <Button + x:Name="startScanButton" + Grid.Row="0" + Click="startScanButton_Click" + Content="Add Device" + FontSize="22" /> + <ListView + Grid.Row="1" + DisplayMemberPath="Name" + ItemsSource="{Binding Devices}" /> + </Grid> +</Page> diff --git a/Signal-Windows/Views/DeviceSettingsPage.xaml.cs b/Signal-Windows/Views/DeviceSettingsPage.xaml.cs new file mode 100644 index 0000000..c0c327d --- /dev/null +++ b/Signal-Windows/Views/DeviceSettingsPage.xaml.cs @@ -0,0 +1,96 @@ +using Signal_Windows.ViewModels; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using Windows.Foundation; +using Windows.Foundation.Collections; +using Windows.UI.Core; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Navigation; + +// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238 + +namespace Signal_Windows.Views +{ + /// <summary> + /// An empty page that can be used on its own or navigated to within a Frame. + /// </summary> + public sealed partial class DeviceSettingsPage : Page + { + public DeviceSettingsPage() + { + this.InitializeComponent(); + } + + public DeviceSettingsPageViewmodel Vm + { + get { return (DeviceSettingsPageViewmodel)this.DataContext; } + } + + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + Utils.EnableBackButton(this.BackButton_Click); + this.Vm.OnNavigatedTo(); + Application.Current.Suspending += this.App_Suspending; + } + + protected override void OnNavigatingFrom(NavigatingCancelEventArgs e) + { + Utils.DisableBackButton(this.BackButton_Click); + Application.Current.Suspending -= this.App_Suspending; + } + + private async void App_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e) + { + var deferral = e.SuspendingOperation.GetDeferral(); + await this.scanner.Cleanup(); + this.ScannerPopup.IsOpen = false; + deferral.Complete(); + } + + + private void BackButton_Click(object sender, BackRequestedEventArgs e) + { + this.Frame.GoBack(); + e.Handled = true; + } + + + private async void CodeFound(string barcode) + { + this.ScannerPopup.IsOpen = false; + await this.Vm.AddDevice(new Uri(barcode)); + } + + private void OnError(Exception e) + { + + } + + private async void startScanButton_Click(object sender, RoutedEventArgs e) + { + ScannerPopup.IsOpen = true; + await this.scanner.StartScan(); + } + + private void root_SizeChanged(object sender, SizeChangedEventArgs e) + { + this.scanner.Width = this.root.ActualWidth; + this.scanner.Height = this.root.ActualHeight; + } + + private void scanner_Cancled() + { + this.ScannerPopup.IsOpen = false; + + } + } +} diff --git a/Signal-Windows/Views/GlobalSettingsPage.xaml b/Signal-Windows/Views/GlobalSettingsPage.xaml index e7796a5..8b3128d 100644 --- a/Signal-Windows/Views/GlobalSettingsPage.xaml +++ b/Signal-Windows/Views/GlobalSettingsPage.xaml @@ -54,6 +54,12 @@ <TextBlock Text="Chats & Media" Style="{StaticResource TitleTextBlockStyle}" Margin="8,0,0,0"/> </StackPanel> </Button> + <Button x:Name="LinkedDevices" Background="{x:Null}" HorizontalContentAlignment="Left" Width="250" Click="LinkedDevices_Click"> + <StackPanel Orientation="Horizontal"> + <FontIcon Glyph="" FontSize="36"/> + <TextBlock Text="Linked Devices" Style="{StaticResource TitleTextBlockStyle}" Margin="8,0,0,0"/> + </StackPanel> + </Button> <Button x:Name="AdvancedButton" Background="{x:Null}" HorizontalContentAlignment="Left" Width="250" Click="AdvancedButton_Click"> <StackPanel Orientation="Horizontal"> <FontIcon Glyph="" FontSize="36"/> diff --git a/Signal-Windows/Views/GlobalSettingsPage.xaml.cs b/Signal-Windows/Views/GlobalSettingsPage.xaml.cs index 44f3d08..60674b8 100644 --- a/Signal-Windows/Views/GlobalSettingsPage.xaml.cs +++ b/Signal-Windows/Views/GlobalSettingsPage.xaml.cs @@ -79,5 +79,10 @@ private void AboutButton_Click(object sender, RoutedEventArgs e) { Frame.Navigate(typeof(AboutPage)); } + + private void LinkedDevices_Click(object sender, RoutedEventArgs e) + { + Frame.Navigate(typeof(DeviceSettingsPage)); + } } } From 8d05df6a495cbad86367a10f56d9266f3a8df437 Mon Sep 17 00:00:00 2001 From: Patrick Kranz <patrick-kranz@live.de> Date: Sun, 16 May 2021 14:37:13 +0200 Subject: [PATCH 2/2] Working on device linking --- Signal-Windows/Controls/QRScanner.cs | 16 +++++-- Signal-Windows/Controls/QRScanner.xaml | 4 +- .../ViewModels/DeviceSettingsPageViewmodel.cs | 43 ++++++++++++----- .../Views/AdvancedSettingsPage.xaml | 46 +++++++++---------- 4 files changed, 69 insertions(+), 40 deletions(-) diff --git a/Signal-Windows/Controls/QRScanner.cs b/Signal-Windows/Controls/QRScanner.cs index 4d362c1..a7c531b 100644 --- a/Signal-Windows/Controls/QRScanner.cs +++ b/Signal-Windows/Controls/QRScanner.cs @@ -154,8 +154,17 @@ private async Task StartPreview() } var focusControl = this.mediaCapture.VideoDeviceController.FocusControl; - if (focusControl.FocusChangedSupported) + if (focusControl.Supported && focusControl.FocusChangedSupported) { + + var state = focusControl.FocusState; + var mode = focusControl.Mode; + var presset = focusControl.Preset; + var modes = focusControl.SupportedFocusModes.ToArray(); + var presets = focusControl.SupportedPresets.ToArray(); + + + this.isReady = false; this.isScanning = true; @@ -185,6 +194,7 @@ private async Task StartPreview() } else { + var capabilits = this.mediaCapture.VideoDeviceController.Focus.Capabilities; await this.OnErrorAsync(new NotSupportedException("AutoFocus control is not supported on this device")); } @@ -321,7 +331,7 @@ private async void UserControl_Unloaded(object sender, RoutedEventArgs e) public async Task StartScan() { - this.btnBarcodeCancel.IsEnabled = false; + this.cancleButton.IsEnabled = false; this.mediaCapture = new MediaCapture(); this.isInitialized = false; this.isScanning = false; @@ -339,7 +349,7 @@ public async Task StartScan() }; await this.StartPreview(); - this.btnBarcodeCancel.IsEnabled = true; + this.cancleButton.IsEnabled = true; } private void Dispose(bool disposing) diff --git a/Signal-Windows/Controls/QRScanner.xaml b/Signal-Windows/Controls/QRScanner.xaml index 122d65f..eed2b54 100644 --- a/Signal-Windows/Controls/QRScanner.xaml +++ b/Signal-Windows/Controls/QRScanner.xaml @@ -25,8 +25,8 @@ HorizontalAlignment="Center" Orientation="Horizontal"> <Button - x:Name="btnBarcodeCancel" - Click="btnBarcodeCancel_Click" + x:Name="cancleButton" + Click="cancelButton_Click" Content="Cancel" /> </StackPanel> </Grid> diff --git a/Signal-Windows/ViewModels/DeviceSettingsPageViewmodel.cs b/Signal-Windows/ViewModels/DeviceSettingsPageViewmodel.cs index 3073867..967c39b 100644 --- a/Signal-Windows/ViewModels/DeviceSettingsPageViewmodel.cs +++ b/Signal-Windows/ViewModels/DeviceSettingsPageViewmodel.cs @@ -1,10 +1,12 @@ using GalaSoft.MvvmLight; using libsignal; +using libsignal.ecc; using libsignal.util; using libsignalservice; using libsignalservice.messages.multidevice; using libsignalservice.util; using Microsoft.Extensions.Logging; +using Org.BouncyCastle.Crypto.Parameters; using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -46,13 +48,25 @@ public async Task AddDevice(Uri uri) var code = await App.Handle.AccountManager.GetNewDeviceVerificationCodeAsync(); - // I'm not sure where which parameter goes... - // but it failes when the QR code is to old, so the first two are propably correct... - await App.Handle.AccountManager.AddDeviceAsync(toAdd.Uuid, toAdd.IdentetyKey.getPublicKey(), - new IdentityKeyPair(Base64.Decode(App.Handle.Store.IdentityKeyPair)), - Base64.Decode(App.Handle.Store.SignalingKey), - code); + // is the SignalingKey the profileKey??? + var profileKey = Base64.Decode(App.Handle.Store.SignalingKey); + var identityKeyPair = new IdentityKeyPair(Base64.Decode(App.Handle.Store.IdentityKeyPair)); + + try + { + // I'm not sure where which parameter goes... + // but it failes when the QR code is to old, so the first two are propably correct... + await App.Handle.AccountManager.AddDeviceAsync(toAdd.Uuid, toAdd.PublicKey, + identityKeyPair, + profileKey, + code); + } + catch (libsignalservice.push.exceptions.NotFoundException) + { + + // ToDo: Handle Divice not found + } await this.RefreshList(); } @@ -61,14 +75,14 @@ await App.Handle.AccountManager.AddDeviceAsync(toAdd.Uuid, toAdd.IdentetyKey.get public class DeviceProtocoll { - private DeviceProtocoll(string uuid, IdentityKey identetyKey) + private DeviceProtocoll(string uuid, ECPublicKey identetyKey) { this.Uuid = uuid; - this.IdentetyKey = identetyKey; + this.PublicKey = identetyKey; } public string Uuid { get; } - public IdentityKey IdentetyKey { get; } + public ECPublicKey PublicKey { get; } public static DeviceProtocoll FromUri(Uri uri) { @@ -104,9 +118,14 @@ public static DeviceProtocoll FromUri(Uri uri) } - var publicKeyBytes = Base64.Decode(Uri.UnescapeDataString(pub_key)); - var identetyKey = new IdentityKey(publicKeyBytes, 0); - return new DeviceProtocoll(uuid, identetyKey); + uuid = Uri.UnescapeDataString(uuid); + + var publicKeyBytes = Base64.DecodeWithoutPadding(Uri.UnescapeDataString(pub_key)); + + + var publicKey = Curve.decodePoint(publicKeyBytes, 0); + + return new DeviceProtocoll(uuid, publicKey); } } diff --git a/Signal-Windows/Views/AdvancedSettingsPage.xaml b/Signal-Windows/Views/AdvancedSettingsPage.xaml index 7047690..7f3f8d0 100644 --- a/Signal-Windows/Views/AdvancedSettingsPage.xaml +++ b/Signal-Windows/Views/AdvancedSettingsPage.xaml @@ -1,24 +1,24 @@ -<Page - x:Class="Signal_Windows.Views.AdvancedSettingsPage" - xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:local="using:Signal_Windows.Views" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - mc:Ignorable="d" - Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" - DataContext="{Binding AdvancedSettingsPageInstance, Source={StaticResource Locator}}"> - - <Grid> - <Grid.RowDefinitions> - <RowDefinition Height="1*"/> - <RowDefinition Height="8*"/> - </Grid.RowDefinitions> - <TextBlock Text="Advanced" HorizontalAlignment="Center" VerticalAlignment="Center" Style="{StaticResource TitleTextBlockStyle}"/> - <StackPanel Grid.Row="1" Margin="32,0,0,0"> - <Button x:Name="ExportDebugLogButton" Content="Export debug log" Click="ExportDebugLogButton_Click"/> +<Page + x:Class="Signal_Windows.Views.AdvancedSettingsPage" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:local="using:Signal_Windows.Views" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + mc:Ignorable="d" + Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" + DataContext="{Binding AdvancedSettingsPageInstance, Source={StaticResource Locator}}"> + + <Grid> + <Grid.RowDefinitions> + <RowDefinition Height="1*"/> + <RowDefinition Height="8*"/> + </Grid.RowDefinitions> + <TextBlock Text="Advanced" HorizontalAlignment="Center" VerticalAlignment="Center" Style="{StaticResource TitleTextBlockStyle}"/> + <StackPanel Grid.Row="1" Margin="32,0,0,0"> + <Button x:Name="ExportDebugLogButton" Content="Export debug log" Click="ExportDebugLogButton_Click"/> <Button x:Name="SyncButton" Content="Request contact and group sync" Margin="0,8,0,0" Click="SyncButton_Click"/> - <Button x:Name="TestCrashButton" Content="Intentionally crash the app to test its debug log export" Click="TestCrashButton_Click"/> - </StackPanel> - </Grid> -</Page> + <Button x:Name="TestCrashButton" Content="Intentionally crash the app to test its debug log export" Click="TestCrashButton_Click"/> + </StackPanel> + </Grid> +</Page>