From 919e40ef6804a1fcdff63657ff3a76fe2a1e2baa Mon Sep 17 00:00:00 2001 From: webwarrior Date: Mon, 3 Apr 2023 16:31:25 +0330 Subject: [PATCH] Frontend(XF,Maui): added remaining pages Added PairingToPage, PairingFromPage, Send, Receive pages. Made PairingFrom page work on Maui by moving configuration of barcode view from .xaml file to code. Use Grid instead of StackLayout so that Maui layout is fixed. Upgrade SendPage layout so that Maui and Xamarin look like each other. Abstracted creation of barcode scanner page to FrontendHelpers.GetBarcodeScannerPage function. Moved platform checking logic to one place (canScanBarcode variable). This removes code duplication between XF and Maui. If QR code is invalid, show alert to the user instead of crashing the app. Fix crash after scanning barcode by checking if modal stack is not empty before calling PopModalAsync(). Co-authored-by: Parham --- .gitignore | 4 ++ scripts/make.fsx | 14 +++- .../GWallet.Frontend.Maui.fsproj | 16 +++++ src/GWallet.Frontend.XF/BalancesPage.xaml.fs | 25 +++----- src/GWallet.Frontend.XF/FrontendHelpers.fs | 31 +++++++++ .../PairingFromPage.xaml.fs | 32 +++++++++- src/GWallet.Frontend.XF/PairingToPage.xaml.fs | 35 ++++++---- src/GWallet.Frontend.XF/ReceivePage.xaml | 2 +- src/GWallet.Frontend.XF/ReceivePage.xaml.fs | 40 ++++++++++-- src/GWallet.Frontend.XF/SendPage.xaml.fs | 64 ++++++++++++------- 10 files changed, 203 insertions(+), 60 deletions(-) diff --git a/.gitignore b/.gitignore index cff268905..61924dfc1 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,7 @@ src/GWallet.Frontend.Maui/WelcomePage.xaml src/GWallet.Frontend.Maui/WelcomePage2.xaml src/GWallet.Frontend.Maui/LoadingPage.xaml src/GWallet.Frontend.Maui/BalancesPage.xaml +src/GWallet.Frontend.Maui/PairingFromPage.xaml +src/GWallet.Frontend.Maui/PairingToPage.xaml +src/GWallet.Frontend.Maui/SendPage.xaml +src/GWallet.Frontend.Maui/ReceivePage.xaml diff --git a/scripts/make.fsx b/scripts/make.fsx index 887508103..e83adcf33 100644 --- a/scripts/make.fsx +++ b/scripts/make.fsx @@ -260,7 +260,17 @@ let BuildSolutionOrProject // TODO: we have to change this function to be the other way around (i.e. copy from Maui to XF) once we // have a finished version of Maui and we consider XF as legacy. let CopyXamlFiles() = - let files = [| "WelcomePage.xaml"; "WelcomePage2.xaml"; "LoadingPage.xaml"; "BalancesPage.xaml" |] + let files = + [| + "WelcomePage.xaml" + "WelcomePage2.xaml" + "LoadingPage.xaml" + "BalancesPage.xaml" + "PairingFromPage.xaml" + "PairingToPage.xaml" + "ReceivePage.xaml" + "SendPage.xaml" + |] for file in files do let sourcePath = Path.Combine("src", "GWallet.Frontend.XF", file) let destPath = Path.Combine("src", "GWallet.Frontend.Maui", file) @@ -271,7 +281,9 @@ let CopyXamlFiles() = destPath, fileText .Replace("http://xamarin.com/schemas/2014/forms","http://schemas.microsoft.com/dotnet/2021/maui") + .Replace("clr-namespace:ZXing.Net.Mobile.Forms;assembly=ZXing.Net.Mobile.Forms","clr-namespace:ZXing.Net.Maui.Controls;assembly=ZXing.Net.MAUI.Controls") .Replace("GWallet.Frontend.XF", "GWallet.Frontend.Maui") + .Replace("ZXingBarcodeImageView", "BarcodeGeneratorView") ) diff --git a/src/GWallet.Frontend.Maui/GWallet.Frontend.Maui.fsproj b/src/GWallet.Frontend.Maui/GWallet.Frontend.Maui.fsproj index c8fb21bad..401bc5ffc 100644 --- a/src/GWallet.Frontend.Maui/GWallet.Frontend.Maui.fsproj +++ b/src/GWallet.Frontend.Maui/GWallet.Frontend.Maui.fsproj @@ -143,6 +143,10 @@ + + + + @@ -150,6 +154,18 @@ + + PairingFromPage.xaml + + + PairingToPage.xaml + + + SendPage.xaml + + + ReceivePage.xaml + BalancesPage.xaml diff --git a/src/GWallet.Frontend.XF/BalancesPage.xaml.fs b/src/GWallet.Frontend.XF/BalancesPage.xaml.fs index 0c7aa03ac..b0834b6f1 100644 --- a/src/GWallet.Frontend.XF/BalancesPage.xaml.fs +++ b/src/GWallet.Frontend.XF/BalancesPage.xaml.fs @@ -35,6 +35,8 @@ open GWallet.Backend open GWallet.Backend.FSharpUtil.UwpHacks +type FiatAmountFrameTapHandler = unit -> unit + // this type allows us to represent the idea that if we have, for example, 3 LTC and an unknown number of ETC (might // be because all ETC servers are unresponsive), then it means we have AT LEAST 3LTC; as opposed to when we know for // sure all balances of all currencies because all servers are responsive @@ -272,14 +274,12 @@ type BalancesPage(state: FrontendHelpers.IGlobalAppState, balances |> Seq.iteri (fun balanceIndex balanceState -> let balanceSet = balanceState.BalanceSet let tapGestureRecognizer = TapGestureRecognizer() -#if XAMARIN tapGestureRecognizer.Tapped.Subscribe(fun _ -> let receivePage () = ReceivePage(balanceSet.Account, readOnly, balanceState.UsdRate, self, balanceSet.Widgets) :> Page FrontendHelpers.SwitchToNewPage self receivePage true ) |> ignore -#endif let frame = balanceSet.Widgets.Frame frame.GestureRecognizers.Add tapGestureRecognizer contentLayout.Children.Add frame @@ -423,7 +423,7 @@ type BalancesPage(state: FrontendHelpers.IGlobalAppState, cancelSource.Cancel() cancelSource.Dispose() - member private self.ConfigureFiatAmountFrame (readOnly: bool): TapGestureRecognizer = + member private self.ConfigureFiatAmountFrame (readOnly: bool): FiatAmountFrameTapHandler = let totalCurrentFiatAmountFrameName,totalOtherFiatAmountFrameName = if readOnly then "totalReadOnlyFiatAmountFrame","totalFiatAmountFrame" @@ -447,9 +447,8 @@ type BalancesPage(state: FrontendHelpers.IGlobalAppState, mainLayout.FindByName otherChartViewName let tapGestureRecognizer = TapGestureRecognizer() -#if XAMARIN - tapGestureRecognizer.Tapped.Add(fun _ -> + let tapHandler () = let shouldNotOpenNewPage = if switchingToReadOnly then readOnlyAccountsBalanceSets.Any() @@ -495,26 +494,22 @@ type BalancesPage(state: FrontendHelpers.IGlobalAppState, PairingFromPage(self, "Copy wallet info to clipboard", walletInfoJson, None) :> Page FrontendHelpers.SwitchToNewPage self page true - - ) -#endif + + tapGestureRecognizer.Tapped.Add(fun _ -> tapHandler()) + totalCurrentFiatAmountFrame.GestureRecognizers.Add tapGestureRecognizer - tapGestureRecognizer + tapHandler member self.PopulateGridInitially () = - let tapper = self.ConfigureFiatAmountFrame false + let tapHandler = self.ConfigureFiatAmountFrame false self.ConfigureFiatAmountFrame true |> ignore self.PopulateBalances false normalBalanceStates RedrawCircleView false normalBalanceStates if startWithReadOnlyAccounts then -#if XAMARIN - tapper.SendTapped null -#else - () // No tapper.SendTapped in MAUI -#endif + tapHandler() member private __.AssignColorLabels (readOnly: bool) = let labels,color = diff --git a/src/GWallet.Frontend.XF/FrontendHelpers.fs b/src/GWallet.Frontend.XF/FrontendHelpers.fs index f88f003a4..0c88300aa 100644 --- a/src/GWallet.Frontend.XF/FrontendHelpers.fs +++ b/src/GWallet.Frontend.XF/FrontendHelpers.fs @@ -24,6 +24,7 @@ open Xamarin.Forms open Xamarin.Essentials open ZXing open ZXing.Mobile +open ZXing.Net.Mobile.Forms #endif open Fsdk open GWallet.Backend @@ -329,7 +330,11 @@ module FrontendHelpers = let SwitchToNewPage (currentPage: Page) (createNewPage: unit -> Page) (navBar: bool): unit = MainThread.BeginInvokeOnMainThread(fun _ -> let newPage = createNewPage () +#if !XAMARIN && GTK + NavigationPage.SetHasNavigationBar(newPage, navBar) +#else NavigationPage.SetHasNavigationBar(newPage, false) +#endif let navPage = NavigationPage newPage NavigationPage.SetHasNavigationBar(navPage, navBar) @@ -482,6 +487,32 @@ module FrontendHelpers = #else BarcodeReaderOptions(TryHarder = true, Formats = BarcodeFormat.QrCode) #endif + + let GetBarcodeScannerPage (onBarcodeDetected: string -> unit) = +#if XAMARIN + let scanPage = ZXingScannerPage BarCodeScanningOptions + scanPage.add_OnScanResult(fun result -> + scanPage.IsScanning <- false + onBarcodeDetected result.Text + ) + scanPage +#else + let scanView = ZXing.Net.Maui.Controls.CameraBarcodeReaderView(Options = BarCodeScanningOptions) + scanView.BarcodesDetected.Add(fun result -> + let barCodeText = result.Results.[0].Value // assume our barcode is first result? + onBarcodeDetected barCodeText + ) + ContentPage(Content = scanView) +#endif + + /// Safer alternative to Navigation.PopModalAsync(): when ModalStack is empty, do nothing. + /// This is used in barcode scanner calbacks because sometimes those would be called more than one time. + let TryPopModalAsync (page: Page) : Task = + if page.Navigation.ModalStack.Count > 0 then + page.Navigation.PopModalAsync() + else + Task.FromResult page + let GetImageSource name = let thisAssembly = typeof.Assembly let thisAssemblyName = thisAssembly.GetName().Name diff --git a/src/GWallet.Frontend.XF/PairingFromPage.xaml.fs b/src/GWallet.Frontend.XF/PairingFromPage.xaml.fs index 4741ce44d..d70204d10 100644 --- a/src/GWallet.Frontend.XF/PairingFromPage.xaml.fs +++ b/src/GWallet.Frontend.XF/PairingFromPage.xaml.fs @@ -1,12 +1,26 @@ -namespace GWallet.Frontend.XF +#if XAMARIN +namespace GWallet.Frontend.XF +#else +namespace GWallet.Frontend.Maui +#endif open System +#if !XAMARIN +open Microsoft.Maui.Controls +open Microsoft.Maui.Controls.Xaml +open Microsoft.Maui.ApplicationModel +open Microsoft.Maui.ApplicationModel.DataTransfer + +open ZXing.Net.Maui +open ZXing.Net.Maui.Controls +#else open Xamarin.Forms open Xamarin.Forms.Xaml open Xamarin.Essentials open ZXing.Net.Mobile.Forms +#endif type PairingFromPage(previousPage: Page, clipBoardButtonCaption: string, @@ -28,13 +42,23 @@ type PairingFromPage(previousPage: Page, let clipBoardButton = mainLayout.FindByName