mirror of
https://github.com/bitwarden/mobile.git
synced 2024-11-26 12:16:07 +01:00
PM-3349 PRM-3350 Replaced XZing with Camera.MAUI for QRCodes
This commit is contained in:
parent
62213c0aaf
commit
f1d59210f9
@ -71,6 +71,7 @@
|
|||||||
<AndroidNativeLibrary Include="Platforms\Android\lib\x86_64\libargon2.so" />
|
<AndroidNativeLibrary Include="Platforms\Android\lib\x86_64\libargon2.so" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Camera.MAUI" Version="1.4.4" />
|
||||||
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
|
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
|
||||||
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
|
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="7.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="7.0.0" />
|
||||||
@ -88,9 +89,7 @@
|
|||||||
<PackageReference Include="Plugin.Fingerprint" Version="2.1.5" />
|
<PackageReference Include="Plugin.Fingerprint" Version="2.1.5" />
|
||||||
<PackageReference Include="SkiaSharp.Views.Maui.Controls" Version="2.88.4-preview.84" />
|
<PackageReference Include="SkiaSharp.Views.Maui.Controls" Version="2.88.4-preview.84" />
|
||||||
<PackageReference Include="SkiaSharp.Views.Maui.Controls.Compatibility" Version="2.88.4-preview.84" />
|
<PackageReference Include="SkiaSharp.Views.Maui.Controls.Compatibility" Version="2.88.4-preview.84" />
|
||||||
<PackageReference Include="ZXing.Net.Maui" Version="0.3.0-preview.1" />
|
|
||||||
<PackageReference Include="FFImageLoadingCompat.Maui" Version="0.1.1" />
|
<PackageReference Include="FFImageLoadingCompat.Maui" Version="0.1.1" />
|
||||||
<PackageReference Include="ZXing.Net.Maui.Controls" Version="0.3.0-preview.1" />
|
|
||||||
<PackageReference Include="AsyncAwaitBestPractices.MVVM" Version="6.0.6" />
|
<PackageReference Include="AsyncAwaitBestPractices.MVVM" Version="6.0.6" />
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1" />
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1" />
|
||||||
<PackageReference Include="PCLCrypto" Version="2.0.147" />
|
<PackageReference Include="PCLCrypto" Version="2.0.147" />
|
||||||
|
@ -45,11 +45,11 @@
|
|||||||
<EmbeddedResource Include="Resources\public_suffix_list.dat" />
|
<EmbeddedResource Include="Resources\public_suffix_list.dat" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Camera.MAUI" Version="1.4.4" />
|
||||||
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
|
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
|
||||||
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
|
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="7.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="7.0.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="ZXing.Net.Maui.Controls" Version="0.3.0-preview.1" />
|
|
||||||
<PackageReference Include="MessagePack" Version="2.5.124" />
|
<PackageReference Include="MessagePack" Version="2.5.124" />
|
||||||
<PackageReference Include="CsvHelper" Version="30.0.1" />
|
<PackageReference Include="CsvHelper" Version="30.0.1" />
|
||||||
<PackageReference Include="LiteDB" Version="5.0.17" />
|
<PackageReference Include="LiteDB" Version="5.0.17" />
|
||||||
@ -70,16 +70,12 @@
|
|||||||
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
|
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">
|
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">
|
||||||
<PackageReference Include="ZXing.Net.Maui" Version="0.3.0-preview.1" />
|
|
||||||
<PackageReference Include="Xamarin.GooglePlayServices.SafetyNet" Version="118.0.1.5" />
|
<PackageReference Include="Xamarin.GooglePlayServices.SafetyNet" Version="118.0.1.5" />
|
||||||
<PackageReference Include="Plugin.CurrentActivity" Version="2.1.0.4" />
|
<PackageReference Include="Plugin.CurrentActivity" Version="2.1.0.4" />
|
||||||
<PackageReference Include="Xamarin.AndroidX.AutoFill" Version="1.1.0.18" />
|
<PackageReference Include="Xamarin.AndroidX.AutoFill" Version="1.1.0.18" />
|
||||||
<PackageReference Include="Xamarin.Firebase.Messaging" Version="123.1.2.2" />
|
<PackageReference Include="Xamarin.Firebase.Messaging" Version="123.1.2.2" />
|
||||||
<PackageReference Include="Xamarin.AndroidX.Activity.Ktx" Version="1.7.2.1" />
|
<PackageReference Include="Xamarin.AndroidX.Activity.Ktx" Version="1.7.2.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">
|
|
||||||
<PackageReference Include="ZXing.Net.Maui" Version="0.3.0-preview.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Services\Logging\" />
|
<Folder Include="Services\Logging\" />
|
||||||
<Folder Include="Attributes\" />
|
<Folder Include="Attributes\" />
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
using CommunityToolkit.Maui;
|
using Camera.MAUI;
|
||||||
|
using CommunityToolkit.Maui;
|
||||||
using FFImageLoading.Maui;
|
using FFImageLoading.Maui;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Maui.Controls.Compatibility.Hosting;
|
using Microsoft.Maui.Controls.Compatibility.Hosting;
|
||||||
using SkiaSharp.Views.Maui.Controls.Hosting;
|
using SkiaSharp.Views.Maui.Controls.Hosting;
|
||||||
using ZXing.Net.Maui.Controls;
|
|
||||||
using AppEffects = Bit.App.Effects;
|
using AppEffects = Bit.App.Effects;
|
||||||
|
|
||||||
namespace Bit.Core;
|
namespace Bit.Core;
|
||||||
@ -20,7 +20,7 @@ public static class MauiProgram
|
|||||||
builder
|
builder
|
||||||
.UseMauiCommunityToolkit()
|
.UseMauiCommunityToolkit()
|
||||||
.UseMauiCompatibility()
|
.UseMauiCompatibility()
|
||||||
.UseBarcodeReader()
|
.UseMauiCameraView()
|
||||||
.UseSkiaSharp()
|
.UseSkiaSharp()
|
||||||
.UseFFImageLoading()
|
.UseFFImageLoading()
|
||||||
.ConfigureEffects(effects =>
|
.ConfigureEffects(effects =>
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using Bit.App.Abstractions;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Bit.App.Abstractions;
|
|
||||||
using Bit.App.Models;
|
using Bit.App.Models;
|
||||||
using Bit.Core.Resources.Localization;
|
using Bit.Core.Resources.Localization;
|
||||||
using Bit.App.Utilities;
|
using Bit.App.Utilities;
|
||||||
@ -9,8 +7,6 @@ using Bit.Core.Enums;
|
|||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Microsoft.Maui.Controls.PlatformConfiguration;
|
using Microsoft.Maui.Controls.PlatformConfiguration;
|
||||||
using Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific;
|
using Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific;
|
||||||
using Microsoft.Maui.Controls;
|
|
||||||
using Microsoft.Maui;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
@ -62,14 +58,12 @@ namespace Bit.App.Pages
|
|||||||
_vm.CipherDetailsPage = cipherDetailsPage;
|
_vm.CipherDetailsPage = cipherDetailsPage;
|
||||||
_vm.Init();
|
_vm.Init();
|
||||||
SetActivityIndicator();
|
SetActivityIndicator();
|
||||||
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
|
if (_vm.EditMode && !_vm.CloneMode && DeviceInfo.Platform == DevicePlatform.Android)
|
||||||
if (_vm.EditMode && !_vm.CloneMode && Device.RuntimePlatform == Device.Android)
|
|
||||||
{
|
{
|
||||||
ToolbarItems.Add(_attachmentsItem);
|
ToolbarItems.Add(_attachmentsItem);
|
||||||
ToolbarItems.Add(_deleteItem);
|
ToolbarItems.Add(_deleteItem);
|
||||||
}
|
}
|
||||||
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
|
if (DeviceInfo.Platform == DevicePlatform.iOS)
|
||||||
if (Device.RuntimePlatform == Device.iOS)
|
|
||||||
{
|
{
|
||||||
ToolbarItems.Add(_closeItem);
|
ToolbarItems.Add(_closeItem);
|
||||||
if (_vm.EditMode && !_vm.CloneMode)
|
if (_vm.EditMode && !_vm.CloneMode)
|
||||||
@ -267,7 +261,7 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
var page = new ScanPage(key =>
|
var page = new ScanPage(key =>
|
||||||
{
|
{
|
||||||
Device.BeginInvokeOnMainThread(async () =>
|
MainThread.BeginInvokeOnMainThread(async () =>
|
||||||
{
|
{
|
||||||
await Navigation.PopModalAsync();
|
await Navigation.PopModalAsync();
|
||||||
await _vm.UpdateTotpKeyAsync(key);
|
await _vm.UpdateTotpKeyAsync(key);
|
||||||
@ -335,8 +329,7 @@ namespace Bit.App.Pages
|
|||||||
if (_vm.Cipher.Type == CipherType.Login && !_fromAutofill && !addLoginShown.GetValueOrDefault())
|
if (_vm.Cipher.Type == CipherType.Login && !_fromAutofill && !addLoginShown.GetValueOrDefault())
|
||||||
{
|
{
|
||||||
await _stateService.SetAddSitePromptShownAsync(true);
|
await _stateService.SetAddSitePromptShownAsync(true);
|
||||||
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
|
if (DeviceInfo.Platform == DevicePlatform.iOS)
|
||||||
if (Device.RuntimePlatform == Device.iOS)
|
|
||||||
{
|
{
|
||||||
if (_deviceActionService.SystemMajorVersion() < 12)
|
if (_deviceActionService.SystemMajorVersion() < 12)
|
||||||
{
|
{
|
||||||
@ -349,9 +342,9 @@ namespace Bit.App.Pages
|
|||||||
AppResources.BitwardenAutofillAlert2, AppResources.Ok);
|
AppResources.BitwardenAutofillAlert2, AppResources.Ok);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Device.RuntimePlatform == Device.Android &&
|
else if (DeviceInfo.Platform == DevicePlatform.Android &&
|
||||||
!_autofillHandler.AutofillAccessibilityServiceRunning() &&
|
!_autofillHandler.AutofillAccessibilityServiceRunning() &&
|
||||||
!_autofillHandler.AutofillServiceEnabled())
|
!_autofillHandler.AutofillServiceEnabled())
|
||||||
{
|
{
|
||||||
await DisplayAlert(AppResources.BitwardenAutofillService,
|
await DisplayAlert(AppResources.BitwardenAutofillService,
|
||||||
AppResources.BitwardenAutofillServiceAlert2, AppResources.Ok);
|
AppResources.BitwardenAutofillServiceAlert2, AppResources.Ok);
|
||||||
@ -362,8 +355,7 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
private void AdjustToolbar()
|
private void AdjustToolbar()
|
||||||
{
|
{
|
||||||
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
|
if ((_vm.EditMode || _vm.CloneMode) && DeviceInfo.Platform == DevicePlatform.Android)
|
||||||
if ((_vm.EditMode || _vm.CloneMode) && Device.RuntimePlatform == Device.Android)
|
|
||||||
{
|
{
|
||||||
if (_vm.Cipher == null)
|
if (_vm.Cipher == null)
|
||||||
{
|
{
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
xmlns:controls="clr-namespace:Bit.App.Controls"
|
xmlns:controls="clr-namespace:Bit.App.Controls"
|
||||||
xmlns:skia="clr-namespace:SkiaSharp.Views.Maui.Controls;assembly=SkiaSharp.Views.Maui.Controls"
|
xmlns:skia="clr-namespace:SkiaSharp.Views.Maui.Controls;assembly=SkiaSharp.Views.Maui.Controls"
|
||||||
xmlns:core="clr-namespace:Bit.Core"
|
xmlns:core="clr-namespace:Bit.Core"
|
||||||
xmlns:zxing="clr-namespace:ZXing.Net.Maui.Controls;assembly=ZXing.Net.MAUI.Controls"
|
xmlns:maui="clr-namespace:Camera.MAUI;assembly=Camera.MAUI"
|
||||||
x:Name="_page"
|
x:Name="_page"
|
||||||
Title="{Binding ScanQrPageTitle}">
|
Title="{Binding ScanQrPageTitle}">
|
||||||
|
|
||||||
@ -34,18 +34,21 @@
|
|||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<!-- TODO: [MAUI-Migration]
|
<maui:CameraView x:Name="_cameraView"
|
||||||
OnScanResult="OnScanResult"-->
|
AutomationId="zxingScannerView"
|
||||||
<zxing:CameraBarcodeReaderView
|
HorizontalOptions="Fill"
|
||||||
x:Name="_zxing"
|
VerticalOptions="Fill"
|
||||||
HorizontalOptions="FillAndExpand"
|
ControlBarcodeResultDuplicate="True"
|
||||||
VerticalOptions="FillAndExpand"
|
BarCodeDetectionEnabled="True"
|
||||||
AutomationId="zxingScannerView"
|
BarcodeDetected="CameraViewOnBarcodeDetected"
|
||||||
IsVisible="{Binding ShowScanner}"
|
BarCodeOptions="{Binding BarCodeOptions}"
|
||||||
Grid.Column="0"
|
Cameras="{Binding Cameras, Mode=OneWayToSource}"
|
||||||
Grid.Row="0"
|
Camera="{Binding Camera}"
|
||||||
Grid.RowSpan="3"
|
AutoStartPreview="{Binding AutoStartPreview}"
|
||||||
BarcodesDetected="_zxing_BarcodesDetected"/>
|
NumCamerasDetected="{Binding NumCameras, Mode=OneWayToSource}"
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.RowSpan="3" />
|
||||||
<StackLayout
|
<StackLayout
|
||||||
VerticalOptions="Center"
|
VerticalOptions="Center"
|
||||||
HorizontalOptions="FillAndExpand"
|
HorizontalOptions="FillAndExpand"
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
using Bit.App.Utilities;
|
using Bit.App.Utilities;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
using Camera.MAUI.ZXingHelper;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
using SkiaSharp.Views.Maui;
|
using SkiaSharp.Views.Maui;
|
||||||
using ZXing.Net.Maui;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
@ -12,8 +12,6 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
private ScanPageViewModel ViewModel => BindingContext as ScanPageViewModel;
|
private ScanPageViewModel ViewModel => BindingContext as ScanPageViewModel;
|
||||||
private readonly Action<string> _callback;
|
private readonly Action<string> _callback;
|
||||||
private CancellationTokenSource _autofocusCts;
|
|
||||||
private Task _continuousAutofocusTask;
|
|
||||||
private readonly Color _greenColor;
|
private readonly Color _greenColor;
|
||||||
private readonly SKColor _blueSKColor;
|
private readonly SKColor _blueSKColor;
|
||||||
private readonly SKColor _greenSKColor;
|
private readonly SKColor _greenSKColor;
|
||||||
@ -27,10 +25,8 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
_callback = callback;
|
_callback = callback;
|
||||||
ViewModel.InitScannerCommand = new Command(() => InitScanner());
|
|
||||||
|
|
||||||
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
|
if (DeviceInfo.Platform == DevicePlatform.Android)
|
||||||
if (Device.RuntimePlatform == Device.Android)
|
|
||||||
{
|
{
|
||||||
ToolbarItems.RemoveAt(0);
|
ToolbarItems.RemoveAt(0);
|
||||||
}
|
}
|
||||||
@ -54,125 +50,47 @@ namespace Bit.App.Pages
|
|||||||
base.OnDisappearing();
|
base.OnDisappearing();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix known bug with DelayBetweenAnalyzingFrames & DelayBetweenContinuousScans: https://github.com/Redth/ZXing.Net.Mobile/issues/721
|
|
||||||
private void InitScanner()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!ViewModel.HasCameraPermission || !ViewModel.ShowScanner || _zxing != null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//_zxing = new ZXingScannerView();
|
|
||||||
_zxing.Options = new BarcodeReaderOptions
|
|
||||||
{
|
|
||||||
//UseNativeScanning = true,
|
|
||||||
//PossibleFormats = new List<ZXing.BarcodeFormat> { ZXing.BarcodeFormat.QR_CODE },
|
|
||||||
Formats = BarcodeFormat.QrCode,
|
|
||||||
AutoRotate = false,
|
|
||||||
TryInverted = true,
|
|
||||||
//DelayBetweenAnalyzingFrames = 5,
|
|
||||||
//DelayBetweenContinuousScans = 5
|
|
||||||
};
|
|
||||||
//_scannerContainer.Content = _zxing;
|
|
||||||
StartScanner();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.Value.Exception(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void StartScanner()
|
private void StartScanner()
|
||||||
{
|
{
|
||||||
if (_zxing == null)
|
if (_cameraView == null) { return; }
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//_zxing.OnScanResult -= OnScanResult;
|
ViewModel.StartCameraCommand?.Execute(this);
|
||||||
//_zxing.OnScanResult += OnScanResult;
|
|
||||||
// TODO: [MAUI-Migration] [Critical]
|
|
||||||
//_zxing.IsScanning = true;
|
|
||||||
|
|
||||||
// Fix for Autofocus, now it's done every 2 seconds so that the user does't have to do it
|
|
||||||
// https://github.com/Redth/ZXing.Net.Mobile/issues/414
|
|
||||||
_autofocusCts?.Cancel();
|
|
||||||
_autofocusCts = new CancellationTokenSource(TimeSpan.FromMinutes(3));
|
|
||||||
|
|
||||||
var autofocusCts = _autofocusCts;
|
|
||||||
// this task is needed to be awaited OnDisappearing to avoid some crashes
|
|
||||||
// when changing the value of _zxing.IsScanning
|
|
||||||
_continuousAutofocusTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
while (!autofocusCts.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
await Task.Delay(TimeSpan.FromSeconds(2), autofocusCts.Token);
|
|
||||||
await Device.InvokeOnMainThreadAsync(() =>
|
|
||||||
{
|
|
||||||
if (!autofocusCts.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_zxing.AutoFocus();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.Value.Exception(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (TaskCanceledException) { }
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.Value.Exception(ex);
|
|
||||||
}
|
|
||||||
}, autofocusCts.Token);
|
|
||||||
_pageIsActive = true;
|
_pageIsActive = true;
|
||||||
AnimationLoopAsync();
|
AnimationLoopAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task StopScanner()
|
private async Task StopScanner()
|
||||||
{
|
{
|
||||||
if (_zxing == null)
|
if (_cameraView == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_autofocusCts?.Cancel();
|
_cameraView.BarCodeDetectionEnabled = false;
|
||||||
if (_continuousAutofocusTask != null)
|
|
||||||
{
|
await _cameraView.StopCameraAsync();
|
||||||
await _continuousAutofocusTask;
|
|
||||||
}
|
|
||||||
// TODO: [MAUI-Migration] [Critical]
|
|
||||||
//_zxing.IsScanning = false;
|
|
||||||
//_zxing.OnScanResult -= OnScanResult;
|
|
||||||
_pageIsActive = false;
|
_pageIsActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: [MAUI-Migration] [Critical]
|
private async void CameraViewOnBarcodeDetected(object sender, BarcodeEventArgs e)
|
||||||
private async void _zxing_BarcodesDetected(System.Object sender, ZXing.Net.Maui.BarcodeDetectionEventArgs e)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!e.Results.Any())
|
if (!e.Result.Any())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var result = e.Results[0];
|
var result = e.Result[0];
|
||||||
// Stop analysis until we navigate away so we don't keep reading barcodes
|
// Stop analysis until we navigate away so we don't keep reading barcodes
|
||||||
// TODO: [MAUI-Migration] [Critical]
|
_cameraView.BarCodeDetectionEnabled = false;
|
||||||
//_zxing.IsAnalyzing = false;
|
|
||||||
var text = result?.Value;
|
var text = result?.Text;
|
||||||
if (!string.IsNullOrWhiteSpace(text))
|
if (!string.IsNullOrWhiteSpace(text))
|
||||||
{
|
{
|
||||||
if (text.StartsWith("otpauth://totp"))
|
if (text.StartsWith("otpauth://totp"))
|
||||||
{
|
{
|
||||||
|
if (_qrcodeFound) { return; } //To avoid duplicate barcode detected events
|
||||||
await QrCodeFoundAsync();
|
await QrCodeFoundAsync();
|
||||||
_callback(text);
|
_callback(text);
|
||||||
return;
|
return;
|
||||||
@ -185,6 +103,7 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
if (part.StartsWith("secret="))
|
if (part.StartsWith("secret="))
|
||||||
{
|
{
|
||||||
|
if (_qrcodeFound) { return; } //To avoid duplicate barcode detected events
|
||||||
await QrCodeFoundAsync();
|
await QrCodeFoundAsync();
|
||||||
var subResult = part.Substring(7);
|
var subResult = part.Substring(7);
|
||||||
if (!string.IsNullOrEmpty(subResult))
|
if (!string.IsNullOrEmpty(subResult))
|
||||||
@ -196,7 +115,11 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_callback(null);
|
|
||||||
|
if (!_qrcodeFound)
|
||||||
|
{
|
||||||
|
_callback(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -209,8 +132,6 @@ namespace Bit.App.Pages
|
|||||||
_qrcodeFound = true;
|
_qrcodeFound = true;
|
||||||
Vibration.Vibrate();
|
Vibration.Vibrate();
|
||||||
await Task.Delay(1000);
|
await Task.Delay(1000);
|
||||||
// TODO: [MAUI-Migration] [Critical]
|
|
||||||
//_zxing.IsScanning = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Close_Clicked(object sender, System.EventArgs e)
|
private async void Close_Clicked(object sender, System.EventArgs e)
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
using System;
|
using System.Collections.ObjectModel;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.Core.Resources.Localization;
|
using Bit.Core.Resources.Localization;
|
||||||
using Bit.App.Utilities;
|
using Bit.App.Utilities;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Services;
|
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
using Camera.MAUI;
|
||||||
using Microsoft.Maui.ApplicationModel;
|
using Camera.MAUI.ZXingHelper;
|
||||||
using Microsoft.Maui.Controls;
|
|
||||||
using Microsoft.Maui;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
@ -25,6 +21,7 @@ namespace Bit.App.Pages
|
|||||||
public ScanPageViewModel()
|
public ScanPageViewModel()
|
||||||
{
|
{
|
||||||
ToggleScanModeCommand = new AsyncCommand(ToggleScanMode, onException: HandleException);
|
ToggleScanModeCommand = new AsyncCommand(ToggleScanMode, onException: HandleException);
|
||||||
|
StartCameraCommand = new Command(StartCamera);
|
||||||
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
||||||
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
||||||
_logger = ServiceContainer.Resolve<ILogger>();
|
_logger = ServiceContainer.Resolve<ILogger>();
|
||||||
@ -35,29 +32,80 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Device.InvokeOnMainThreadAsync(async () =>
|
await MainThread.InvokeOnMainThreadAsync(async () =>
|
||||||
{
|
{
|
||||||
var hasCameraPermission = await PermissionManager.CheckAndRequestPermissionAsync(new Permissions.Camera());
|
var hasCameraPermission = await PermissionManager.CheckAndRequestPermissionAsync(new Permissions.Camera());
|
||||||
HasCameraPermission = hasCameraPermission == PermissionStatus.Granted;
|
HasCameraPermission = hasCameraPermission == PermissionStatus.Granted;
|
||||||
ShowScanner = hasCameraPermission == PermissionStatus.Granted;
|
ShowScanner = hasCameraPermission == PermissionStatus.Granted;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!HasCameraPermission)
|
BarCodeOptions = new BarcodeDecodeOptions
|
||||||
{
|
{
|
||||||
return;
|
AutoRotate = false, //shouldn't be needed for QRCodes
|
||||||
}
|
PossibleFormats = { ZXing.BarcodeFormat.QR_CODE },
|
||||||
InitScannerCommand.Execute(null);
|
ReadMultipleCodes = false, //runs slower when true and we only need one
|
||||||
|
TryHarder = false, //runs slower when true
|
||||||
|
TryInverted = true
|
||||||
|
};
|
||||||
|
TriggerPropertyChanged(nameof(BarCodeOptions));
|
||||||
}
|
}
|
||||||
catch (System.Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
HandleException(ex);
|
HandleException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ICommand ToggleScanModeCommand { get; set; }
|
private CameraInfo _camera = null;
|
||||||
public ICommand InitScannerCommand { get; set; }
|
public CameraInfo Camera
|
||||||
|
{
|
||||||
|
get => _camera;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_camera = value;
|
||||||
|
TriggerPropertyChanged(nameof(Camera));
|
||||||
|
|
||||||
|
StartCameraCommand?.Execute(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private ObservableCollection<CameraInfo> _cameras = new();
|
||||||
|
public ObservableCollection<CameraInfo> Cameras
|
||||||
|
{
|
||||||
|
get => _cameras;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_cameras = value;
|
||||||
|
TriggerPropertyChanged(nameof(Cameras));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public int NumCameras
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value > 0)
|
||||||
|
{
|
||||||
|
Camera = Cameras.First();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BarcodeDecodeOptions BarCodeOptions { get; set; }
|
||||||
|
public bool AutoStartPreview { get; set; } = false;
|
||||||
|
|
||||||
|
public ICommand StartCameraCommand { get; set; }
|
||||||
|
public ICommand ToggleScanModeCommand { get; set; }
|
||||||
|
|
||||||
|
private bool _hasCameraPermission = false;
|
||||||
|
public bool HasCameraPermission
|
||||||
|
{
|
||||||
|
get => _hasCameraPermission;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_hasCameraPermission = value;
|
||||||
|
|
||||||
|
StartCameraCommand?.Execute(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool HasCameraPermission { get; set; }
|
|
||||||
public string ScanQrPageTitle => ShowScanner ? AppResources.ScanQrTitle : AppResources.AuthenticatorKeyScanner;
|
public string ScanQrPageTitle => ShowScanner ? AppResources.ScanQrTitle : AppResources.AuthenticatorKeyScanner;
|
||||||
public string CameraInstructionTop => ShowScanner ? AppResources.PointYourCameraAtTheQRCode : AppResources.OnceTheKeyIsSuccessfullyEntered;
|
public string CameraInstructionTop => ShowScanner ? AppResources.PointYourCameraAtTheQRCode : AppResources.OnceTheKeyIsSuccessfullyEntered;
|
||||||
public string TotpAuthenticationKey
|
public string TotpAuthenticationKey
|
||||||
@ -81,6 +129,23 @@ namespace Bit.App.Pages
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void StartCamera()
|
||||||
|
{
|
||||||
|
if (HasCameraPermission && Camera != null)
|
||||||
|
{
|
||||||
|
// Note: If we need to improve performance on Android we can use _cameraView.StartCamera() directly on ScanPage.xaml.cs
|
||||||
|
// this allows us to set a specific smaller resolution that should help performance and time to scan.
|
||||||
|
// (The supported resolutions are available in the Camera object)
|
||||||
|
// This solution would likely replace the "AutoStartPreview" logic in this Command.
|
||||||
|
|
||||||
|
//Setting AutoStartPreview to false and then true should trigger the CameraView to start
|
||||||
|
AutoStartPreview = false;
|
||||||
|
TriggerPropertyChanged(nameof(AutoStartPreview));
|
||||||
|
AutoStartPreview = true;
|
||||||
|
TriggerPropertyChanged(nameof(AutoStartPreview));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ToggleScanMode()
|
private async Task ToggleScanMode()
|
||||||
{
|
{
|
||||||
var cameraPermission = await PermissionManager.CheckAndRequestPermissionAsync(new Permissions.Camera());
|
var cameraPermission = await PermissionManager.CheckAndRequestPermissionAsync(new Permissions.Camera());
|
||||||
@ -95,7 +160,6 @@ namespace Bit.App.Pages
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ShowScanner = !ShowScanner;
|
ShowScanner = !ShowScanner;
|
||||||
InitScannerCommand.Execute(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public FormattedString ToggleScanModeLabel
|
public FormattedString ToggleScanModeLabel
|
||||||
@ -119,7 +183,7 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
private void HandleException(Exception ex)
|
private void HandleException(Exception ex)
|
||||||
{
|
{
|
||||||
Microsoft.Maui.ApplicationModel.MainThread.InvokeOnMainThreadAsync(async () =>
|
MainThread.InvokeOnMainThreadAsync(async () =>
|
||||||
{
|
{
|
||||||
await _deviceActionService.HideLoadingAsync();
|
await _deviceActionService.HideLoadingAsync();
|
||||||
await _platformUtilsService.ShowDialogAsync(AppResources.GenericErrorMessage);
|
await _platformUtilsService.ShowDialogAsync(AppResources.GenericErrorMessage);
|
||||||
|
Loading…
Reference in New Issue
Block a user