From 7748941680a6460738fccf49c794db784900ee2d Mon Sep 17 00:00:00 2001 From: Andy Howard Date: Wed, 24 Apr 2024 17:18:05 +0100 Subject: [PATCH] Saxonite 1.2.11.3. Sandtrap. --- SaCommonVS.sln | 18 +- SacsCoreUnitTests/SacsCoreUnitTests.csproj | 1 - .../Standard/Base/Generic/Regex_Tester.cs | 41 ++- SacsCoreWeb/Web/Components/SaController.cs | 15 +- SacsMobileMaui/Maui/App/Sam.cs | 208 +++++++++++++ SacsMobileMaui/Maui/App/SamApplication.cs | 60 ++++ SacsMobileMaui/Maui/Base/SamComponents.cs | 54 ++++ .../Maui/Consoles/SamWebServiceConsole.cs | 30 ++ .../Maui/Controls/Panels/SamCheckBoxPanel.cs | 147 +++++++++ .../Maui/Controls/Panels/SamControlPanel.cs | 162 ++++++++++ .../Maui/Controls/Panels/SamEntryPanel.cs | 179 +++++++++++ SacsMobileMaui/Maui/Controls/SamButton.cs | 36 +++ SacsMobileMaui/Maui/Controls/SamCheckBox.cs | 33 ++ SacsMobileMaui/Maui/Controls/SamDatePicker.cs | 221 ++++++++++++++ .../Maui/Controls/SamDateTimePicker.cs | 160 ++++++++++ SacsMobileMaui/Maui/Controls/SamEditor.cs | 84 +++++ SacsMobileMaui/Maui/Controls/SamEntry.cs | 167 ++++++++++ .../Maui/Controls/SamImageButton.cs | 40 +++ SacsMobileMaui/Maui/Controls/SamLabel.cs | 78 +++++ SacsMobileMaui/Maui/Controls/SamPicker.cs | 178 +++++++++++ SacsMobileMaui/Maui/Controls/SamTabControl.cs | 193 ++++++++++++ SacsMobileMaui/Maui/Controls/SamTimePicker.cs | 53 ++++ SacsMobileMaui/Maui/Controls/SamWebView.cs | 103 +++++++ .../Maui/Handlers/SamFormHandler.cs | 139 +++++++++ .../Maui/Layouts/SamAbsoluteLayout.cs | 30 ++ SacsMobileMaui/Maui/Layouts/SamFlexLayout.cs | 30 ++ .../Maui/Layouts/SamGrid.cs | 30 +- SacsMobileMaui/Maui/Layouts/SamStackLayout.cs | 30 ++ SacsMobileMaui/Maui/Layouts/SamWrapLayout.cs | 249 +++++++++++++++ SacsMobileMaui/Maui/Pages/SamContentPage.cs | 182 +++++++++++ SacsMobileMaui/Maui/Panels/SamPanel.cs | 81 +++++ .../Maui/Panels/SamPanel_ItemFilter.cs | 169 +++++++++++ .../Panels/SamPanel_ItemFilterProperty.cs | 174 +++++++++++ .../Maui/Panels/SamPanel_ItemListHeader.cs | 286 ++++++++++++++++++ .../Maui/Panels/SamPanel_ItemListSummary.cs | 128 ++++++++ .../Maui/Panels/SamPanel_Messages.cs | 77 +++++ .../Maui/Panels/SamPanel_Page_Footer.cs | 135 +++++++++ .../Maui/Panels/SamPanel_Page_Header.cs | 205 +++++++++++++ .../Maui/Panels/SamPanel_Progress.cs | 94 ++++++ .../Maui/Panels/SamPanel_PropertySummary.cs | 141 +++++++++ SacsMobileMaui/Maui/Panels/SamPanel_Tab.cs | 82 +++++ SacsMobileMaui/Maui/Panels/SamPanel_Tabbed.cs | 212 +++++++++++++ SacsMobileMaui/Maui/Panels/SamTabPanel.cs | 52 ++++ SacsMobileMaui/Maui/Utils/SamElementUtil.cs | 29 ++ SacsMobileMaui/Maui/Utils/SamFormUtil.cs | 49 +++ SacsMobileMaui/Maui/Utils/SamImageUtil.cs | 25 ++ SacsMobileMaui/Maui/Utils/SamPageUtil.cs | 18 ++ SacsMobileMaui/Maui/Utils/SamResourceUtil.cs | 61 ++++ SacsMobileMaui/Maui/Utils/SamThreadUtil.cs | 69 +++++ SacsMobileMaui/Maui/Utils/SamTimerUtil.cs | 28 ++ SacsMobileMaui/Maui/Views/ISamView.cs | 28 ++ SacsMobileMaui/Maui/Views/SamBorder.cs | 46 +++ SacsMobileMaui/Maui/Views/SamBoxView.cs | 46 +++ SacsMobileMaui/Maui/Views/SamContentView.cs | 70 +++++ SacsMobileMaui/Maui/Views/SamFrame.cs | 46 +++ SacsMobileMaui/Maui/Views/SamView.cs | 46 +++ .../Platforms/Android/PlatformClass1.cs | 7 + .../Platforms/MacCatalyst/PlatformClass1.cs | 7 + .../Platforms/Tizen/PlatformClass1.cs | 9 + .../Platforms/Windows/PlatformClass1.cs | 7 + .../Platforms/iOS/PlatformClass1.cs | 7 + SacsMobileMaui/SacsMobileMaui.csproj | 32 ++ .../SacsMobileXamarin.csproj | 2 +- .../Xamarin}/App/SaxApplication.cs | 3 +- .../Xamarin}/Forms/Base/SaxComponents.cs | 2 +- .../Xamarin}/Forms/Controls/SaxButton.cs | 2 +- .../Xamarin}/Forms/Controls/SaxDatePicker.cs | 6 +- .../Forms/Controls/SaxDateTimePicker.cs | 8 +- .../Xamarin}/Forms/Controls/SaxEditor.cs | 2 +- .../Xamarin}/Forms/Controls/SaxEntry.cs | 2 +- .../Xamarin}/Forms/Controls/SaxImageButton.cs | 2 +- .../Xamarin}/Forms/Controls/SaxLabel.cs | 2 +- .../Xamarin}/Forms/Controls/SaxPicker.cs | 22 +- .../Xamarin}/Forms/Controls/SaxTabControl.cs | 8 +- .../Xamarin}/Forms/Controls/SaxTimePicker.cs | 2 +- .../Xamarin}/Forms/Controls/SaxWebView.cs | 2 +- .../Forms/Layouts/SaxAbsoluteLayout.cs | 2 +- .../Xamarin}/Forms/Layouts/SaxFlexLayout.cs | 2 +- .../Xamarin/Forms/Layouts/SaxGrid.cs | 66 ++++ .../Xamarin}/Forms/Layouts/SaxStackLayout.cs | 2 +- .../Xamarin}/Forms/Layouts/SaxWrapLayout.cs | 2 +- .../Xamarin}/Forms/Pages/SaxContentPage.cs | 2 +- .../Xamarin}/Forms/Panels/SaxPanel.cs | 4 +- .../Forms/Panels/SaxPanel_ItemFilter.cs | 7 +- .../Panels/SaxPanel_ItemFilterProperty.cs | 10 +- .../Forms/Panels/SaxPanel_ItemListHeader.cs | 65 ++-- .../Forms/Panels/SaxPanel_ItemListSummary.cs | 16 +- .../Forms/Panels/SaxPanel_Messages.cs | 9 +- .../Forms/Panels/SaxPanel_Progress.cs | 12 +- .../Forms/Panels/SaxPanel_PropertySummary.cs | 12 +- .../Xamarin}/Forms/Panels/SaxTabPanel.cs | 4 +- .../Xamarin}/Forms/Utils/SaxFormsUtil.cs | 4 +- .../Xamarin}/Forms/Utils/SaxPageUtil.cs | 2 +- .../Xamarin}/Forms/Views/SaxBoxView.cs | 2 +- .../Xamarin}/Forms/Views/SaxContentView.cs | 2 +- .../Xamarin}/Forms/Views/SaxFrame.cs | 2 +- .../Xamarin}/Forms/Views/SaxView.cs | 2 +- .../Xamarin}/Tasks/SaxThreadUtil.cs | 2 +- .../Xamarin}/Utils/ImageUtils.cs | 2 +- .../Base/Helpers/SacsResourceHelper.cs | 51 ++-- SacsStandardBase/Base/IO/DirectoryUtil.cs | 9 + SacsStandardBase/Base/Utils/AssemblyUtil.cs | 11 +- SacsStandardBase/Base/Utils/StringUtil.cs | 2 +- SacsStandardBase/SacsStandardBase.csproj | 4 +- 104 files changed, 5615 insertions(+), 177 deletions(-) create mode 100644 SacsMobileMaui/Maui/App/Sam.cs create mode 100644 SacsMobileMaui/Maui/App/SamApplication.cs create mode 100644 SacsMobileMaui/Maui/Base/SamComponents.cs create mode 100644 SacsMobileMaui/Maui/Consoles/SamWebServiceConsole.cs create mode 100644 SacsMobileMaui/Maui/Controls/Panels/SamCheckBoxPanel.cs create mode 100644 SacsMobileMaui/Maui/Controls/Panels/SamControlPanel.cs create mode 100644 SacsMobileMaui/Maui/Controls/Panels/SamEntryPanel.cs create mode 100644 SacsMobileMaui/Maui/Controls/SamButton.cs create mode 100644 SacsMobileMaui/Maui/Controls/SamCheckBox.cs create mode 100644 SacsMobileMaui/Maui/Controls/SamDatePicker.cs create mode 100644 SacsMobileMaui/Maui/Controls/SamDateTimePicker.cs create mode 100644 SacsMobileMaui/Maui/Controls/SamEditor.cs create mode 100644 SacsMobileMaui/Maui/Controls/SamEntry.cs create mode 100644 SacsMobileMaui/Maui/Controls/SamImageButton.cs create mode 100644 SacsMobileMaui/Maui/Controls/SamLabel.cs create mode 100644 SacsMobileMaui/Maui/Controls/SamPicker.cs create mode 100644 SacsMobileMaui/Maui/Controls/SamTabControl.cs create mode 100644 SacsMobileMaui/Maui/Controls/SamTimePicker.cs create mode 100644 SacsMobileMaui/Maui/Controls/SamWebView.cs create mode 100644 SacsMobileMaui/Maui/Handlers/SamFormHandler.cs create mode 100644 SacsMobileMaui/Maui/Layouts/SamAbsoluteLayout.cs create mode 100644 SacsMobileMaui/Maui/Layouts/SamFlexLayout.cs rename SacsStandardMob/Mobile/Forms/Layouts/SaxGrid.cs => SacsMobileMaui/Maui/Layouts/SamGrid.cs (63%) create mode 100644 SacsMobileMaui/Maui/Layouts/SamStackLayout.cs create mode 100644 SacsMobileMaui/Maui/Layouts/SamWrapLayout.cs create mode 100644 SacsMobileMaui/Maui/Pages/SamContentPage.cs create mode 100644 SacsMobileMaui/Maui/Panels/SamPanel.cs create mode 100644 SacsMobileMaui/Maui/Panels/SamPanel_ItemFilter.cs create mode 100644 SacsMobileMaui/Maui/Panels/SamPanel_ItemFilterProperty.cs create mode 100644 SacsMobileMaui/Maui/Panels/SamPanel_ItemListHeader.cs create mode 100644 SacsMobileMaui/Maui/Panels/SamPanel_ItemListSummary.cs create mode 100644 SacsMobileMaui/Maui/Panels/SamPanel_Messages.cs create mode 100644 SacsMobileMaui/Maui/Panels/SamPanel_Page_Footer.cs create mode 100644 SacsMobileMaui/Maui/Panels/SamPanel_Page_Header.cs create mode 100644 SacsMobileMaui/Maui/Panels/SamPanel_Progress.cs create mode 100644 SacsMobileMaui/Maui/Panels/SamPanel_PropertySummary.cs create mode 100644 SacsMobileMaui/Maui/Panels/SamPanel_Tab.cs create mode 100644 SacsMobileMaui/Maui/Panels/SamPanel_Tabbed.cs create mode 100644 SacsMobileMaui/Maui/Panels/SamTabPanel.cs create mode 100644 SacsMobileMaui/Maui/Utils/SamElementUtil.cs create mode 100644 SacsMobileMaui/Maui/Utils/SamFormUtil.cs create mode 100644 SacsMobileMaui/Maui/Utils/SamImageUtil.cs create mode 100644 SacsMobileMaui/Maui/Utils/SamPageUtil.cs create mode 100644 SacsMobileMaui/Maui/Utils/SamResourceUtil.cs create mode 100644 SacsMobileMaui/Maui/Utils/SamThreadUtil.cs create mode 100644 SacsMobileMaui/Maui/Utils/SamTimerUtil.cs create mode 100644 SacsMobileMaui/Maui/Views/ISamView.cs create mode 100644 SacsMobileMaui/Maui/Views/SamBorder.cs create mode 100644 SacsMobileMaui/Maui/Views/SamBoxView.cs create mode 100644 SacsMobileMaui/Maui/Views/SamContentView.cs create mode 100644 SacsMobileMaui/Maui/Views/SamFrame.cs create mode 100644 SacsMobileMaui/Maui/Views/SamView.cs create mode 100644 SacsMobileMaui/Platforms/Android/PlatformClass1.cs create mode 100644 SacsMobileMaui/Platforms/MacCatalyst/PlatformClass1.cs create mode 100644 SacsMobileMaui/Platforms/Tizen/PlatformClass1.cs create mode 100644 SacsMobileMaui/Platforms/Windows/PlatformClass1.cs create mode 100644 SacsMobileMaui/Platforms/iOS/PlatformClass1.cs create mode 100644 SacsMobileMaui/SacsMobileMaui.csproj rename SacsStandardMob/SacsStandardMob.csproj => SacsMobileXamarin/SacsMobileXamarin.csproj (88%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/App/SaxApplication.cs (97%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Base/SaxComponents.cs (96%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Controls/SaxButton.cs (95%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Controls/SaxDatePicker.cs (97%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Controls/SaxDateTimePicker.cs (96%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Controls/SaxEditor.cs (97%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Controls/SaxEntry.cs (98%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Controls/SaxImageButton.cs (94%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Controls/SaxLabel.cs (95%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Controls/SaxPicker.cs (89%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Controls/SaxTabControl.cs (97%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Controls/SaxTimePicker.cs (97%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Controls/SaxWebView.cs (98%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Layouts/SaxAbsoluteLayout.cs (93%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Layouts/SaxFlexLayout.cs (93%) create mode 100644 SacsMobileXamarin/Xamarin/Forms/Layouts/SaxGrid.cs rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Layouts/SaxStackLayout.cs (93%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Layouts/SaxWrapLayout.cs (99%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Pages/SaxContentPage.cs (98%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Panels/SaxPanel.cs (96%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Panels/SaxPanel_ItemFilter.cs (97%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Panels/SaxPanel_ItemFilterProperty.cs (95%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Panels/SaxPanel_ItemListHeader.cs (85%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Panels/SaxPanel_ItemListSummary.cs (91%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Panels/SaxPanel_Messages.cs (91%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Panels/SaxPanel_Progress.cs (92%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Panels/SaxPanel_PropertySummary.cs (93%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Panels/SaxTabPanel.cs (93%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Utils/SaxFormsUtil.cs (93%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Utils/SaxPageUtil.cs (89%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Views/SaxBoxView.cs (93%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Views/SaxContentView.cs (97%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Views/SaxFrame.cs (93%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Forms/Views/SaxView.cs (93%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Tasks/SaxThreadUtil.cs (96%) rename {SacsStandardMob/Mobile => SacsMobileXamarin/Xamarin}/Utils/ImageUtils.cs (94%) diff --git a/SaCommonVS.sln b/SaCommonVS.sln index b611761..af93996 100644 --- a/SaCommonVS.sln +++ b/SaCommonVS.sln @@ -7,8 +7,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SacsStandardBase", "SacsSta EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SacsStandardDbas", "SacsStandardDbas\SacsStandardDbas.csproj", "{14768EB5-6FA5-4F62-9347-44A667A760C1}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SacsStandardMob", "SacsStandardMob\SacsStandardMob.csproj", "{E507AB63-28E3-4FF4-9EA8-2E87C42FFC20}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SacsCoreWeb", "SacsCoreWeb\SacsCoreWeb.csproj", "{AE8FCC39-D13D-4E32-995E-C69352F9F95E}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SacsCoreUnitTests", "SacsCoreUnitTests\SacsCoreUnitTests.csproj", "{70F1302F-E8F2-49CB-A09D-889DA59681DD}" @@ -22,6 +20,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SacsStandardAccounts", "Sac EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SacsStandardProc", "SacsStandardProc\SacsStandardProc.csproj", "{3988EE9F-FFCD-481A-AF5E-AA7E5DB5A415}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SacsMobileXamarin", "SacsMobileXamarin\SacsMobileXamarin.csproj", "{8DB58994-2E78-4F87-8630-63A3C7F5D8BD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SacsMobileMaui", "SacsMobileMaui\SacsMobileMaui.csproj", "{F167BCF8-8B99-4103-A710-D4B8FD5518A7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -36,10 +38,6 @@ Global {14768EB5-6FA5-4F62-9347-44A667A760C1}.Debug|Any CPU.Build.0 = Debug|Any CPU {14768EB5-6FA5-4F62-9347-44A667A760C1}.Release|Any CPU.ActiveCfg = Release|Any CPU {14768EB5-6FA5-4F62-9347-44A667A760C1}.Release|Any CPU.Build.0 = Release|Any CPU - {E507AB63-28E3-4FF4-9EA8-2E87C42FFC20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E507AB63-28E3-4FF4-9EA8-2E87C42FFC20}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E507AB63-28E3-4FF4-9EA8-2E87C42FFC20}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E507AB63-28E3-4FF4-9EA8-2E87C42FFC20}.Release|Any CPU.Build.0 = Release|Any CPU {AE8FCC39-D13D-4E32-995E-C69352F9F95E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AE8FCC39-D13D-4E32-995E-C69352F9F95E}.Debug|Any CPU.Build.0 = Debug|Any CPU {AE8FCC39-D13D-4E32-995E-C69352F9F95E}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -56,6 +54,14 @@ Global {3988EE9F-FFCD-481A-AF5E-AA7E5DB5A415}.Debug|Any CPU.Build.0 = Debug|Any CPU {3988EE9F-FFCD-481A-AF5E-AA7E5DB5A415}.Release|Any CPU.ActiveCfg = Release|Any CPU {3988EE9F-FFCD-481A-AF5E-AA7E5DB5A415}.Release|Any CPU.Build.0 = Release|Any CPU + {8DB58994-2E78-4F87-8630-63A3C7F5D8BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8DB58994-2E78-4F87-8630-63A3C7F5D8BD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8DB58994-2E78-4F87-8630-63A3C7F5D8BD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8DB58994-2E78-4F87-8630-63A3C7F5D8BD}.Release|Any CPU.Build.0 = Release|Any CPU + {F167BCF8-8B99-4103-A710-D4B8FD5518A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F167BCF8-8B99-4103-A710-D4B8FD5518A7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F167BCF8-8B99-4103-A710-D4B8FD5518A7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F167BCF8-8B99-4103-A710-D4B8FD5518A7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SacsCoreUnitTests/SacsCoreUnitTests.csproj b/SacsCoreUnitTests/SacsCoreUnitTests.csproj index 68a8b4a..8d897ad 100644 --- a/SacsCoreUnitTests/SacsCoreUnitTests.csproj +++ b/SacsCoreUnitTests/SacsCoreUnitTests.csproj @@ -19,7 +19,6 @@ - diff --git a/SacsCoreUnitTests/Standard/Base/Generic/Regex_Tester.cs b/SacsCoreUnitTests/Standard/Base/Generic/Regex_Tester.cs index 38e5cff..98e565b 100644 --- a/SacsCoreUnitTests/Standard/Base/Generic/Regex_Tester.cs +++ b/SacsCoreUnitTests/Standard/Base/Generic/Regex_Tester.cs @@ -8,12 +8,51 @@ namespace Sacs.UnitTests.Net.Standard.Base.Generic { //------------------------------------------------------------------- // Data members. + //------------------------------------------------------------------- [TestMethod] - public void Regex_FolderPaths () + public void Regex_FolderPaths() { Assert.AreEqual(true, Regex.IsMatch("abcabcabc\\.metadata\\.plugins\\abcabcabc", ".*?\\\\\\.metadata\\\\\\.plugins\\\\.*?")); + + // Path ends in. + Assert.AreEqual(true, Regex.IsMatch("D:\\Home\\Data\\Logs\\App", "[\\\\/]app$", RegexOptions.IgnoreCase)); + Assert.AreEqual(true, Regex.IsMatch("/home/data/logs/app", "[\\\\/]app$", RegexOptions.IgnoreCase)); + + // Path doesn't end in. + Assert.AreEqual(false, Regex.IsMatch("D:\\Home\\Data\\Logs", "[\\\\/]app$", RegexOptions.IgnoreCase)); + Assert.AreEqual(false, Regex.IsMatch("/home/data/logs", "[\\\\/]app$", RegexOptions.IgnoreCase)); } + + //------------------------------------------------------------------- + [TestMethod] + public void Regex_IsMatch() + { + string input = "abcdefghi"; + + Assert.AreEqual(true, Regex.IsMatch(input, "a")); + Assert.AreEqual(true, Regex.IsMatch(input, "^a")); + Assert.AreEqual(true, Regex.IsMatch(input, "d")); + Assert.AreEqual(true, Regex.IsMatch(input, "i$")); + + // Combination characters. + Assert.AreEqual(true, Regex.IsMatch(input, "[adg]")); + Assert.AreEqual(true, Regex.IsMatch(input, "[cba]")); + + // Blank matches input. + Assert.AreEqual(true, Regex.IsMatch(input, "")); + + // Characters at incorrect position. + Assert.AreEqual(false, Regex.IsMatch(input, "a$")); + Assert.AreEqual(false, Regex.IsMatch(input, "^d")); + Assert.AreEqual(false, Regex.IsMatch(input, "d$")); + Assert.AreEqual(false, Regex.IsMatch(input, "^i")); + + // Incorrect characters. + Assert.AreEqual(false, Regex.IsMatch(input, "j")); + Assert.AreEqual(false, Regex.IsMatch(input, " ")); + } + //------------------------------------------------------------------- } } diff --git a/SacsCoreWeb/Web/Components/SaController.cs b/SacsCoreWeb/Web/Components/SaController.cs index f4bf7c8..a31853e 100644 --- a/SacsCoreWeb/Web/Components/SaController.cs +++ b/SacsCoreWeb/Web/Components/SaController.cs @@ -41,7 +41,6 @@ namespace Sacs.Web.Components //------------------------------------------------------------------- // Properties. - private static String ClassName { get; } = nameof(SaController); public DateTime CreatedAt { get; } = DateTime.Now; public bool DebugMode { get; } = SacsSystem.DebugMode; /// @@ -125,7 +124,6 @@ namespace Sacs.Web.Components //------------------------------------------------------------------- public static String EncryptParameters(NameValueCollection parameters, String base64IV, String base64Key) { - String fn = ClassName + ".EncryptParameters"; try { // Copy the list of parameters and sort the keys. @@ -140,22 +138,21 @@ namespace Sacs.Web.Components // Encrypt data. String encrypted = SacsEncryptionHelper.Encrypt(queryString, base64IV, base64Key); - //if (SacsSystem.DebugMode) SaLogger.Debug(fn + "\n\tData: " + queryString + " \n\tEncrypted: " + encrypted); + //if (SacsSystem.DebugMode) SaLogger.Debug(SysUtil.Fn + "\n\tData: " + queryString + " \n\tEncrypted: " + encrypted); return encrypted; } - catch (Exception exc) { SaLogger.Warn(fn + " " + ExceptionUtil.GetErrorStateMessage(exc)); } + catch (Exception exc) { SaLogger.Warn(SysUtil.Fn + " " + ExceptionUtil.GetErrorStateMessage(exc)); } return ""; } public static NameValueCollection DecryptParameters(String encrypted, String base64IV, String base64Key) { - String fn = ClassName + ".DecryptParameters"; try { String queryString = SacsEncryptionHelper.Decrypt(encrypted, base64IV, base64Key); - //if (SacsSystem.DebugMode) SaLogger.Debug(fn + " \n\tEncrypted: " + encrypted + "\n\tData: " + queryString); + //if (SacsSystem.DebugMode) SaLogger.Debug(SysUtil.Fn + " \n\tEncrypted: " + encrypted + "\n\tData: " + queryString); return HttpUtility.ParseQueryString(queryString); } - catch (Exception exc) { SaLogger.Warn(fn + " " + ExceptionUtil.GetErrorStateMessage(exc)); } + catch (Exception exc) { SaLogger.Warn(SysUtil.Fn + " " + ExceptionUtil.GetErrorStateMessage(exc)); } return new NameValueCollection(); } @@ -236,7 +233,7 @@ namespace Sacs.Web.Components public MessageData Message { get; private set; } public AjaxResponse_Base SetMessage(String title, String text) { - if (!StringUtil.IsEmpty(text)) + if (!StringUtil.IsBlank(text)) Message = new MessageData() { Title = title, Text = text }; return this; } @@ -368,7 +365,7 @@ namespace Sacs.Web.Components { foreach (FormControlValue controlValue in controlValues.Values) { - if (!StringUtil.IsEmpty(controlValue.Error)) return true; + if (!StringUtil.IsBlank(controlValue.Error)) return true; } return false; } diff --git a/SacsMobileMaui/Maui/App/Sam.cs b/SacsMobileMaui/Maui/App/Sam.cs new file mode 100644 index 0000000..938b6ea --- /dev/null +++ b/SacsMobileMaui/Maui/App/Sam.cs @@ -0,0 +1,208 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.App +{ + //======================================================================= + // Colour references: + // http://www.html-color-names.com/skyblue.php + // http://www.html-color-names.com/lightsteelblue.php + //======================================================================= + public static class Sam + { + //------------------------------------------------------------------- + // Definitions. + public enum Platform + { + Unknown = 0, + Android, + IOS, + MacCatalyst, + Windows + } + // Utilities. + public static Random Random { get; set; } = new Random(); + + //------------------------------------------------------------------- + // Localisation. + public static class Locale + { + public static CultureInfo CultureInfo { get; set; } = CultureInfo.CurrentCulture; + public static TextInfo TextInfo { get; set; } = CultureInfo.TextInfo; + } + + //------------------------------------------------------------------- + // Visuals. + public enum DisplayPosition { None, Left, Middle, Right } + public static class Visuals + { + // Application styling. + public static class Application + { + // Application bar. + public static class Bar + { + public static double Height { get; set; } = 28; + public static Color BackgroundColor { get; set; } = Color.FromArgb("#558395"); + public static Color TextColor { get; set; } = Color.FromArgb("#f8f8f8"); + public static double TextSizeRatio { get; set; } = 1.5; + public static Color BorderColor { get; set; } = Colors.DarkSlateBlue; + public static double BorderBottom { get; set; } = 1.0; + } + // Menu. + public static class Menu + { + public static Color BorderColor { get; set; } = Colors.DarkSlateBlue; + public static double Border { get; set; } = 1.0; + public static Color BackgroundColor { get; set; } = Color.FromArgb("#F0F0F0"); + public static Color HeaderBackgroundColor { get; set; } = Color.FromArgb("#E0E0E0"); + } + } + // Page layout. + public static class Page + { + public static Color BaseColor { get; set; } = Color.FromArgb("#c8e8f5"); + public static Color BackgroundColor { get; set; } = Color.FromArgb("#e9f6fb"); + // Header. + public static class Header + { + // Text. + public static String TextLeft { get; set; } = ""; + public static String TextRight { get; set; } = ""; + // Toolbar. + public static DisplayPosition ToolbarDisplay { get; set; } = Sam.DisplayPosition.None; + public static bool Display_ToolbarItem_Back { get; set; } = false; + // Styling. + public static Color BackgroundColor { get; set; } = Colors.Honeydew; + public static Color BorderColor { get; set; } = Colors.LightSlateGray; + public static double BorderStrokeWidthTop { get; set; } = 2.0; + public static double BorderStrokeWidthBottom { get; set; } = 1.0; + public static Thickness Padding { get; set; } = new Thickness(8, 4); + } + // Caption. + public static class Caption + { + public static Color BackgroundColor { get; set; } = Color.FromArgb("#558395"); + public static double PaddingHorizontal { get; set; } = 4.0; + public static double PaddingVertical { get; set; } = 8.0; + public static Color TextColor { get; set; } = Color.FromArgb("#f8f8f8"); + public static double TextSizeRatio { get; set; } = 1.25; + } + // Navigation. + public static class Navigation + { + public static double BorderTopWidth { get; set; } = 0.75; + public static double PaddingVertical { get; set; } = 4.0; + public static Color BorderColor { get; set; } = Color.FromArgb("#808080"); + public static Color BackgroundColor { get; set; } = Color.FromArgb("#e9f6fb"); + } + // Body. + public static class Body + { + public static double PaddingVerticalMin { get; set; } = 4.0; + public static double PaddingHorizontalMin { get; set; } = 4.0; + } + // Footer. + public static class Footer + { + public static String TextLeft { get; set; } = ""; + public static String TextMiddle { get; set; } = ""; + public static String TextRight { get; set; } = ""; + public static String DateTimeFormat { get; set; } = "ddd d-MMM-yyyy HH:mm:ss"; + public static DisplayPosition DateTimeDisplay { get; set; } = DisplayPosition.None; + public static Color BackgroundColor { get; set; } = Colors.Honeydew; + public static Color BorderColor { get; set; } = Colors.LightSlateGray; + public static double BorderStrokeWidthTop { get; set; } = 1.0; + public static double BorderStrokeWidthBottom { get; set; } = 2.0; + public static Thickness Padding { get; set; } = new Thickness(8, 4); + } + } + // Fonts. + public static class Fonts + { + // Dynamic font sizing. + public static string HtmlFontSize + { + get + { + if (SamApplication.MinDeviceDimension > 2000) return "14pt"; + if (SamApplication.MinDeviceDimension > 1600) return "13pt"; + if (SamApplication.MinDeviceDimension > 1200) return "12pt"; + if (SamApplication.MinDeviceDimension > 1000) return "11pt"; + return "10pt"; + } + } + public static double FontSizeRatio + { + get + { + if (SamApplication.MinDeviceDimension > 2000) return 1.75; + if (SamApplication.MinDeviceDimension > 1600) return 1.50; + if (SamApplication.MinDeviceDimension > 1200) return 1.25; + return 1.0; + } + } + } + // Data display visuals. + public static class Data + { + // Item list. + public static class ItemList + { + public static double HeaderBorderWidth { get; set; } = 2.0; + public static float HeaderBorderRadius = 6.0f; + public static Color HeaderBorderColor = Sam.Visuals.Application.Bar.BackgroundColor; + public static Color HeaderBackgroundColor = Color.FromArgb("#F0F0F0"); + } + // Associated items panel. + public static class AssociatedItems + { + public static Color CaptionBackgroundColor { get; set; } = Color.FromArgb("#becee4"); + public static Color CaptionTextColor { get; set; } = Color.FromArgb("#f8f8f8"); + public static double CaptionTextSizeRatio { get; set; } = 1.2; + public static Color BackgroundColor { get; set; } = Color.FromArgb("#dbe4f0"); + } + } + // Form. + public static class Form + { + public static Color BackgroundColor { get; set; } = Color.FromArgb("#e9f6fb"); + public static double GridRowSpacing { get; set; } = 4.0; + public static double GridColumnSpacing { get; set; } = 4.0; + // Label. + public static class Label + { + public static Thickness Margin { get; set; } = new Thickness(8.0, 4.0, 8.0, 2.0); + } + // Controls. + public static class Controls + { + public static Thickness Padding { get; set; } = new Thickness(4.0, 2.0, 4.0, 1.0); + public static Color BackgroundColor { get; set; } = Color.FromArgb("#F8F8F8"); + public static Color BorderColor { get; set; } = Color.FromArgb("#E0E0E0"); + public static double BorderWidth { get; set; } = 0.5; + // Native behaviour modified by SamHandler. + public static bool NativeNoBorder { get; set; } = false; + public static bool NativeNoUnderline { get; set; } = false; + public static bool NativeBackgroundClear { get; set; } = false; + } + // Tab controls. + public static class TabControl + { + public static Color HeaderBackgroundColor { get; set; } = Colors.Transparent; + public static Color CaptionBackgroundColor { get; set; } = Color.FromArgb("#E0E0E0"); + public static Color BodyBackgroundColor { get; set; } = Color.FromArgb("#F8F8F8"); + public static Thickness BodyPadding { get; set; } = new Thickness(4.0); + } + } + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/App/SamApplication.cs b/SacsMobileMaui/Maui/App/SamApplication.cs new file mode 100644 index 0000000..947bc94 --- /dev/null +++ b/SacsMobileMaui/Maui/App/SamApplication.cs @@ -0,0 +1,60 @@ +using Sarand.Net.Standard.Base.App; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.App +{ + //======================================================================= + public class SamApplication : Application + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + private Sam.Platform platform; + + //------------------------------------------------------------------- + protected SamApplication() + { + // Determine platform. +#if ANDROID + platform = Sam.Platform.Android; +#elif IOS + platform = Sam.Platform.IOS; +#elif MACCATALYST + platform = Sam.Platform.MacCatalyst; +#elif WINDOWS + platform = Sam.Platform.Windows; +#endif + + // Log environment. + SaLogger.Debug("Platform: " + platform.ToString()); + SaLogger.Debug("AppInfo.AppName: " + AppInfo.Name); + SaLogger.Debug("AppInfo.PackageName: " + AppInfo.PackageName); + SaLogger.Debug("AppInfo.Version: " + AppInfo.VersionString); + SaLogger.Debug("AppInfo.Build: " + AppInfo.BuildString); + SaLogger.Debug("DeviceWidth: " + DeviceWidth); + SaLogger.Debug("DeviceHeight: " + DeviceHeight); + SaLogger.Debug("DeviceDensity: " + DeviceDisplay.MainDisplayInfo.Density); + } + + //------------------------------------------------------------------- + // Properties. + + public Sam.Platform Platform { get { return platform; } } + + // Device screen size and orientation. + public static bool Landscape => DeviceWidth > DeviceHeight; + public static double DeviceWidth => DeviceDisplay.MainDisplayInfo.Width; + public static double DeviceHeight => DeviceDisplay.MainDisplayInfo.Height; + public static double MinDeviceDimension => Math.Min(DeviceWidth, DeviceHeight); + public static double MaxDeviceDimension => Math.Max(DeviceWidth, DeviceHeight); + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Base/SamComponents.cs b/SacsMobileMaui/Maui/Base/SamComponents.cs new file mode 100644 index 0000000..868951a --- /dev/null +++ b/SacsMobileMaui/Maui/Base/SamComponents.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Base +{ + //======================================================================= + public class SamComponents + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + private bool readOnly = false; + + //------------------------------------------------------------------- + // Construction. + public SamComponents() + { + } + + //------------------------------------------------------------------- + // Properties. + public bool ReadOnly + { + get { return readOnly; } + set { if (readOnly == value) return; readOnly = value; SetControlsReadOnly(); } + } + public bool Changed { get; protected set; } = false; + + //------------------------------------------------------------------- + // C o n f i g u r e C o m p o n e n t s + //------------------------------------------------------------------- + protected virtual void ConfigureComponents() + { + } + + //------------------------------------------------------------------- + // C o n t r o l A c t i v i t y + //------------------------------------------------------------------- + protected virtual void SetControlActivity() + { + } + protected virtual void SetControlsReadOnly() + { + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Consoles/SamWebServiceConsole.cs b/SacsMobileMaui/Maui/Consoles/SamWebServiceConsole.cs new file mode 100644 index 0000000..eee48d3 --- /dev/null +++ b/SacsMobileMaui/Maui/Consoles/SamWebServiceConsole.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Consoles +{ + //====================================================================== + public class SamWebServiceConsole + { + //------------------------------------------------------------------ + // Definitions. + + //------------------------------------------------------------------ + // Data members. + + //------------------------------------------------------------------ + // Construction. + protected SamWebServiceConsole() + { + } + + //------------------------------------------------------------------ + // Properties. + + //------------------------------------------------------------------ + } + //====================================================================== +} diff --git a/SacsMobileMaui/Maui/Controls/Panels/SamCheckBoxPanel.cs b/SacsMobileMaui/Maui/Controls/Panels/SamCheckBoxPanel.cs new file mode 100644 index 0000000..48210cc --- /dev/null +++ b/SacsMobileMaui/Maui/Controls/Panels/SamCheckBoxPanel.cs @@ -0,0 +1,147 @@ +using Sarand.Net.Mobile.Maui.Controls.Views; +using Sarand.Net.Standard.Base.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Controls.Panels +{ + //======================================================================= + public class SamCheckBoxPanel : SamControlPanel + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + private readonly SamCheckBox checkbox = new SamCheckBox() { }; + private readonly TapGestureRecognizer gestureSuffixTap = new TapGestureRecognizer() { }; + + //------------------------------------------------------------------- + // Construction. + public SamCheckBoxPanel() + { + // View configuration. + HorizontalOptions = LayoutOptions.Start; + + // Control configuration. + BorderThickness = 0; + BorderColor = Colors.Transparent; + BackgroundColor = Colors.Transparent; + + // Checkbox events. + checkbox.Focused += Entry_Focused; + checkbox.Unfocused += Entry_Unfocused; + checkbox.CheckedChanged += Checkbox_CheckedChanged; + gestureSuffixTap.Tapped += GestureSuffixTap_Tapped; + LabelSuffix.GestureRecognizers.Add(gestureSuffixTap); + + ConfigureComponents(); + SetControlActivity(); + } + + //------------------------------------------------------------------- + // Properties. + protected override View ControlView { get { return checkbox; } } + public bool IsChecked + { + get { return checkbox.IsChecked; } + set { if (checkbox.IsChecked == value) return; checkbox.IsChecked = value; } + } + public new LayoutOptions HorizontalOptions + { + get { return checkbox.HorizontalOptions; } + set { checkbox.HorizontalOptions = value; ReadOnlyLabel.HorizontalOptions = checkbox.HorizontalOptions; } + } + + //------------------------------------------------------------------- + // C o n f i g u r e C o m p o n e n t s + //------------------------------------------------------------------- + /// Control configuration that can be changed dynamically. + public override void ConfigureComponents() + { + base.ConfigureComponents(); + } + + //------------------------------------------------------------------- + // C o n t r o l A c t i v i t y + //------------------------------------------------------------------- + public override void SetControlActivity() + { + base.SetControlActivity(); + SetControlsReadOnly(); + } + public override void SetControlsReadOnly() + { + base.SetControlsReadOnly(); + } + + //------------------------------------------------------------------- + // C o n t r o l E v e n t s + //------------------------------------------------------------------- + private void Entry_Focused(object? sender, FocusEventArgs e) + { + Control_Focused(sender, e); + } + //------------------------------------------------------------------- + private void Entry_Unfocused(object? sender, FocusEventArgs e) + { + Control_Unfocused(sender, e); + } + //------------------------------------------------------------------- + // Checked changed. + public event EventHandler? CheckedChanged; + private void Checkbox_CheckedChanged(object? sender, CheckedChangedEventArgs e) + { + ReadOnlyText = checkbox.IsChecked ? "X" : ""; + if (ReadOnly) return; + if (CheckedChanged != null) CheckedChanged.Invoke(sender, e); + } + + private void GestureSuffixTap_Tapped(object? sender, TappedEventArgs e) + { + checkbox.IsChecked = !checkbox.IsChecked; + } + + //------------------------------------------------------------------- + // V i e w E v e n t s + //------------------------------------------------------------------- + protected override void OnParentSet() + { + base.OnParentSet(); + } + + //------------------------------------------------------------------- + protected override void OnPropertyChanging([CallerMemberName] string propertyName = "") + { + base.OnPropertyChanging(propertyName); + } + protected override void OnPropertyChanged([CallerMemberName] string propertyName = "") + { + base.OnPropertyChanged(propertyName); + //Logger.Debug(GetType().Name + ".OnPropertyChanged Name=" + propertyName); + } + + //------------------------------------------------------------------- + protected override void OnChildAdded(Element child) + { + base.OnChildAdded(child); + } + protected override void OnChildRemoved(Element child, int oldLogicalIndex) + { + base.OnChildRemoved(child, oldLogicalIndex); + } + + //------------------------------------------------------------------- + protected override void OnSizeAllocated(double width, double height) + { + base.OnSizeAllocated(width, height); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Controls/Panels/SamControlPanel.cs b/SacsMobileMaui/Maui/Controls/Panels/SamControlPanel.cs new file mode 100644 index 0000000..7d780a0 --- /dev/null +++ b/SacsMobileMaui/Maui/Controls/Panels/SamControlPanel.cs @@ -0,0 +1,162 @@ +using Sarand.Net.Mobile.Maui.App; +using Sarand.Net.Mobile.Maui.Views; +using Sarand.Net.Standard.Base.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Controls.Views +{ + //======================================================================= + public abstract class SamControlPanel : SamContentView + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + // Components. + private HorizontalStackLayout controlLayout = new HorizontalStackLayout(); + private SamContentView controlBorder = new SamContentView(); + private SamContentView controlPanel = new SamContentView() { Padding = Sam.Visuals.Form.Controls.Padding }; + // Styling. + private Thickness controlBorderThickness = new Thickness(Sam.Visuals.Form.Controls.BorderWidth); + private Color controlBorderColor = Sam.Visuals.Form.Controls.BorderColor; + private Color controlBackgroundColor = Sam.Visuals.Form.Controls.BackgroundColor; + + //------------------------------------------------------------------- + // Construction. + protected SamControlPanel() + { + // Control layout: [Border[Panel]] [Suffix]. + controlBorder.Content = controlPanel; + controlLayout.Add(controlBorder); + controlLayout.Add(LabelSuffix); + + // Main layout. + Content = controlLayout; + + SetControlActivity(); + } + + //------------------------------------------------------------------- + // Properties. + + // Label. + public SamLabel Label { get; } = new SamLabel() { Margin = Sam.Visuals.Form.Label.Margin }; + public String LabelText { get { return Label.Text; } set { if (Label.Text.Equals(value)) return; Label.Text = value; } } + + // Control. + /// The control itself. NB May be composite + protected abstract View ControlView { get; } + /// Control used for read-only display. + protected SamLabel ReadOnlyLabel { get; } = + new SamLabel() { BackgroundColor = Colors.Transparent }; + + // Suffix. + protected SamLabel LabelSuffix { get; } = new SamLabel() { Margin = Sam.Visuals.Form.Label.Margin }; + public String SuffixText { get { return LabelSuffix.Text; } set { if (LabelSuffix.Text.Equals(value)) return; LabelSuffix.Text = value; } } + public double SuffixPadding { get { return LabelSuffix.Padding.Left; } set { if (LabelSuffix.Padding.Left == value) return; LabelSuffix.Padding = new(value, 0, 0, 0); } } + + // Styling. + public new Color BackgroundColor + { + get { return controlBackgroundColor; } + set { controlBackgroundColor = value; ConfigureComponents(); } + } + public Thickness BorderThickness + { + get { return controlBorderThickness; } + set { controlBorderThickness = value; ConfigureComponents(); } + } + public double BorderWidth + { + set { BorderThickness = new Thickness(value); } + } + public Color BorderColor + { + get { return controlBorderColor; } + set { controlBorderColor = value; } + } + public new LayoutOptions HorizontalOptions + { + get { return base.HorizontalOptions; } + set { base.HorizontalOptions = value; ControlView.HorizontalOptions = value; } + } + protected String ReadOnlyText + { + get { return ReadOnlyLabel.Text; } + set { if (ReadOnlyLabel.Text.Equals(value)) return; ReadOnlyLabel.Text = value; } + } + + //------------------------------------------------------------------- + // C o n f i g u r e C o m p o n e n t s + //------------------------------------------------------------------- + /// Control configuration that can be changed dynamically. + public override void ConfigureComponents() + { + // Outer view acts as border. + controlBorder.BackgroundColor = controlBorderColor; + controlBorder.Padding = controlBorderThickness; + controlPanel.BackgroundColor = controlBackgroundColor; + } + + //------------------------------------------------------------------- + // C o n t r o l A c t i v i t y + //------------------------------------------------------------------- + public override void SetControlActivity() + { + base.SetControlActivity(); + } + public override void SetControlsReadOnly() + { + base.SetControlsReadOnly(); + if (ReadOnly) controlPanel.Content = ReadOnlyLabel; + else controlPanel.Content = ControlView; + } + + //------------------------------------------------------------------- + // C o n t r o l E v e n t s + //------------------------------------------------------------------- + public new event EventHandler? Focused; + protected void Control_Focused(object? sender, FocusEventArgs e) + { + if (Focused != null) Focused.Invoke(sender, e); + } + //------------------------------------------------------------------- + public new event EventHandler? Unfocused; + protected void Control_Unfocused(object? sender, FocusEventArgs e) + { + if (Unfocused != null) Unfocused.Invoke(sender, e); + } + + //------------------------------------------------------------------- + // V i e w E v e n t s + //------------------------------------------------------------------- + protected override void OnPropertyChanged([CallerMemberName] string propertyName = "") + { + base.OnPropertyChanged(propertyName); + //Logger.Debug(GetType().Name + ".OnPropertyChanged Name=" + propertyName); + + if (propertyName.EqualsCI(PaddingProperty.PropertyName)) + { + if (!controlPanel.Padding.Equals(Padding)) + { + // Apply the padding to the embedded view and clear this view's padding. + controlPanel.Padding = Padding; + Padding = new Thickness(); + } + } + else if (propertyName.EqualsCI(BackgroundColorProperty.PropertyName)) + { + controlPanel.BackgroundColor = BackgroundColor; + } + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Controls/Panels/SamEntryPanel.cs b/SacsMobileMaui/Maui/Controls/Panels/SamEntryPanel.cs new file mode 100644 index 0000000..6a6ee41 --- /dev/null +++ b/SacsMobileMaui/Maui/Controls/Panels/SamEntryPanel.cs @@ -0,0 +1,179 @@ +using Sarand.Net.Standard.Base.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Controls.Views +{ + //======================================================================= + public class SamEntryPanel : SamControlPanel + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + private readonly SamEntry entry = new SamEntry() { HorizontalOptions = LayoutOptions.Fill }; + + //------------------------------------------------------------------- + // Construction. + public SamEntryPanel() + { + // View configuration. + HorizontalOptions = LayoutOptions.Start; + + // Control configuration. + entry.BackgroundColor = Colors.Transparent; + + // Entry events. + entry.Focused += Entry_Focused; + entry.Unfocused += Entry_Unfocused; + entry.TextChanged += Entry_TextChanged; + entry.Completed += Entry_Completed; + + SetControlActivity(); + } + + //------------------------------------------------------------------- + // Properties. + protected override View ControlView { get { return entry; } } + public int MaxLength + { + get { return entry.MaxLength; } + set { entry.MaxLength = value; } + } + public SamEntry.TextCaseType TextCase + { + get { return entry.TextCase; } + set { entry.TextCase = value; } + } + public bool NumericOnly + { + get { return entry.NumericOnly; } + set { entry.NumericOnly = value; ReadOnlyLabel.HorizontalTextAlignment = entry.HorizontalTextAlignment; } + } + public byte Decimals + { + get { return entry.Decimals; } + set { entry.Decimals = value; ReadOnlyLabel.HorizontalTextAlignment = entry.HorizontalTextAlignment; } + } + public Keyboard Keyboard + { + get { return entry.Keyboard; } + set { entry.Keyboard = value; } + } + public bool IsPassword + { + get { return entry.IsPassword; } + set { entry.IsPassword = value; } + } + public String Text + { + get { return entry.Text; } + set { value = StringUtil.EmptyOnNull(value); if (entry.Text != null && entry.Text.Equals(value)) return; entry.Text = value; } + } + public new double WidthRequest + { + get { return entry.WidthRequest; } + set { entry.WidthRequest = value; ReadOnlyLabel.WidthRequest = value; } + } + public TextAlignment HorizontalTextAlignment + { + get { return entry.HorizontalTextAlignment; } + set { entry.HorizontalTextAlignment = value; ReadOnlyLabel.HorizontalTextAlignment = entry.HorizontalTextAlignment; } + } + + //------------------------------------------------------------------- + // C o n f i g u r e C o m p o n e n t s + //------------------------------------------------------------------- + /// Control configuration that can be changed dynamically. + public override void ConfigureComponents() + { + base.ConfigureComponents(); + } + + //------------------------------------------------------------------- + // C o n t r o l A c t i v i t y + //------------------------------------------------------------------- + public override void SetControlActivity() + { + base.SetControlActivity(); + SetControlsReadOnly(); + } + public override void SetControlsReadOnly() + { + base.SetControlsReadOnly(); + } + + //------------------------------------------------------------------- + // C o n t r o l E v e n t s + //------------------------------------------------------------------- + private void Entry_Focused(object? sender, FocusEventArgs e) + { + Control_Focused(sender, e); + } + //------------------------------------------------------------------- + private void Entry_Unfocused(object? sender, FocusEventArgs e) + { + Control_Unfocused(sender, e); + } + //------------------------------------------------------------------- + // Text changed. + public event EventHandler? TextChanged; + private void Entry_TextChanged(object? sender, TextChangedEventArgs e) + { + ReadOnlyText = entry.Text; + if (ReadOnly) return; + if (TextChanged != null) TextChanged.Invoke(sender, e); + } + //------------------------------------------------------------------- + // Completed. + public event EventHandler? Completed; + private void Entry_Completed(object? sender, EventArgs e) + { + if (ReadOnly) return; + if (Completed != null) Completed.Invoke(sender, e); + } + + //------------------------------------------------------------------- + // V i e w E v e n t s + //------------------------------------------------------------------- + protected override void OnParentSet() + { + base.OnParentSet(); + } + + //------------------------------------------------------------------- + protected override void OnPropertyChanging([CallerMemberName] string propertyName = "") + { + base.OnPropertyChanging(propertyName); + } + protected override void OnPropertyChanged([CallerMemberName] string propertyName = "") + { + base.OnPropertyChanged(propertyName); + //Logger.Debug(GetType().Name + ".OnPropertyChanged Name=" + propertyName); + } + + //------------------------------------------------------------------- + protected override void OnChildAdded(Element child) + { + base.OnChildAdded(child); + } + protected override void OnChildRemoved(Element child, int oldLogicalIndex) + { + base.OnChildRemoved(child, oldLogicalIndex); + } + + //------------------------------------------------------------------- + protected override void OnSizeAllocated(double width, double height) + { + base.OnSizeAllocated(width, height); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Controls/SamButton.cs b/SacsMobileMaui/Maui/Controls/SamButton.cs new file mode 100644 index 0000000..a6ef2f1 --- /dev/null +++ b/SacsMobileMaui/Maui/Controls/SamButton.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Controls +{ + //======================================================================= + public class SamButton : Button + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + + //------------------------------------------------------------------- + // Construction. + public SamButton() + { + DefaultFontSize = FontSize; + } + + //------------------------------------------------------------------- + // Properties. + public double DefaultFontSize { get; } + + //------------------------------------------------------------------- + // C o n t r o l E v e n t s + //------------------------------------------------------------------- + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Controls/SamCheckBox.cs b/SacsMobileMaui/Maui/Controls/SamCheckBox.cs new file mode 100644 index 0000000..04a4b93 --- /dev/null +++ b/SacsMobileMaui/Maui/Controls/SamCheckBox.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Controls +{ + //====================================================================== + public class SamCheckBox : CheckBox + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + + //------------------------------------------------------------------- + // Construction. + public SamCheckBox() + { + } + + //------------------------------------------------------------------- + // Properties. + + //------------------------------------------------------------------- + // Control events. + + //------------------------------------------------------------------- + } + //====================================================================== +} diff --git a/SacsMobileMaui/Maui/Controls/SamDatePicker.cs b/SacsMobileMaui/Maui/Controls/SamDatePicker.cs new file mode 100644 index 0000000..7d5b183 --- /dev/null +++ b/SacsMobileMaui/Maui/Controls/SamDatePicker.cs @@ -0,0 +1,221 @@ +using Sarand.Net.Mobile.Maui.Layouts; +using Sarand.Net.Mobile.Maui.Views; +using Sarand.Net.Standard.Base.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Controls +{ + //======================================================================= + public class SamDatePicker : SamContentView + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + private bool allowInvalidDate = false; + private bool invalidDate = true; + private DateTime previousDate = DateTime.MinValue; + private SamStackLayout controlLayout = new SamStackLayout() { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.Fill }; + private DatePicker pickerDate = new DatePicker() { IsVisible = false }; + private SamEntry entryDate = new SamEntry() { HorizontalOptions = LayoutOptions.FillAndExpand, VerticalOptions = LayoutOptions.Fill }; + private SamLabel labelResetDate = new SamLabel() { Text = "X", FontAttributes = FontAttributes.Bold, TextColor = Colors.Red, HorizontalOptions = LayoutOptions.Center, VerticalTextAlignment = TextAlignment.Center }; + + //------------------------------------------------------------------- + // Construction. + public SamDatePicker() + { + // Initialise controls. + // Date picker. Hidden but used to display calendar. + DefaultFontSize = pickerDate.FontSize; + pickerDate.Format = "dd-MMM-yyyy"; + pickerDate.DateSelected += PickerDate_DateSelected; + // Date display entry. + entryDate.FontSize = pickerDate.FontSize; + entryDate.FontFamily = pickerDate.FontFamily; + entryDate.FontAttributes = pickerDate.FontAttributes; + entryDate.TextColor = pickerDate.TextColor; + entryDate.Focused += EntryDate_Focused; + // 'Reset' date label - to invalidate the date value. + labelResetDate.FontSize = pickerDate.FontSize; + labelResetDate.FontFamily = pickerDate.FontFamily; + + // 'Reset' label tap gesture. + var tapGestureRecognizer = new TapGestureRecognizer(); + tapGestureRecognizer.Tapped += LabelValidDate_Tapped; + labelResetDate.GestureRecognizers.Add(tapGestureRecognizer); + + // Initialise layout. + Content = controlLayout; + controlLayout.Children.Add(pickerDate); + controlLayout.Children.Add(entryDate); + controlLayout.Children.Add(labelResetDate); + + RefreshDateDisplay(); + } + + //------------------------------------------------------------------- + // Properties. + // Configuration. + public Boolean AllowInvalid + { + get { return allowInvalidDate; } + set + { + if (allowInvalidDate = value) return; + allowInvalidDate = value; + if (!allowInvalidDate) invalidDate = false; + RefreshDateDisplay(); + } + } + public string Format + { + get { return pickerDate.Format; } + set + { + if (pickerDate.Format.Equals(value)) return; + pickerDate.Format = value; + } + } + public DateTime MinimumDate + { + get { return pickerDate.MinimumDate; } + set { pickerDate.MinimumDate = value; } + } + public DateTime MaximumDate + { + get { return pickerDate.MaximumDate; } + set { pickerDate.MaximumDate = value; } + } + //------------------------------------------------------------------- + // Date value. + public DateTime Date + { + get + { + if (invalidDate) return DateTime.MinValue; + return pickerDate.Date; + } + set + { + if (Date.Equals(value)) return; + if (!DateUtil.IsValid(value)) + { + invalidDate = true; + pickerDate.Date = DateTime.Today; + } + else + { + invalidDate = false; + pickerDate.Date = value; + } + previousDate = value; + } + } + public String FormattedDate { get { return !invalidDate ? DateUtil.Format(Date, pickerDate.Format) : ""; } } + //------------------------------------------------------------------- + // Font. + public double DefaultFontSize { get; } + public double FontSize + { + get { return pickerDate.FontSize; } + set + { + if (pickerDate.FontSize == value) return; + pickerDate.FontSize = value; + entryDate.FontSize = value; + } + } + public String FontFamily + { + get { return pickerDate.FontFamily; } + set + { + if (pickerDate.FontFamily == value) return; + pickerDate.FontFamily = value; + entryDate.FontFamily = value; + } + } + public FontAttributes FontAttributes + { + get { return pickerDate.FontAttributes; } + set + { + if (pickerDate.FontAttributes == value) return; + pickerDate.FontAttributes = value; + entryDate.FontAttributes = value; + } + } + public Color TextColor + { + get { return pickerDate.TextColor; } + set + { + if (pickerDate.TextColor == value) return; + pickerDate.TextColor = value; + entryDate.TextColor = value; + } + } + + //------------------------------------------------------------------- + // Utilities. + private void RefreshDateDisplay() + { + if (allowInvalidDate) + { + pickerDate.IsVisible = false; + entryDate.IsVisible = true; + labelResetDate.IsVisible = true; + } + else + { + pickerDate.IsVisible = true; + entryDate.IsVisible = false; + labelResetDate.IsVisible = false; + } + String dateValue = ""; + if (!invalidDate) + dateValue = DateUtil.Format(Date, pickerDate.Format); + entryDate.Text = dateValue; + } + + //------------------------------------------------------------------- + // C o n t r o l E v e n t s + //------------------------------------------------------------------- + private void PickerDate_DateSelected(object? sender, DateChangedEventArgs e) + { + // Date has changed in control. + invalidDate = !DateUtil.IsValid(e.NewDate); + RefreshDateDisplay(); + if (DateSelected != null) DateSelected.Invoke(sender, e); + } + public event EventHandler? DateSelected; + //------------------------------------------------------------------- + private void EntryDate_Focused(object? sender, FocusEventArgs e) + { + // Control has gained focus. + entryDate.Unfocus(); + pickerDate.Focus(); + invalidDate = false; + RefreshDateDisplay(); + } + //------------------------------------------------------------------- + private void LabelValidDate_Tapped(object? sender, EventArgs e) + { + // 'Valid' label tapped. + if (invalidDate) return; + invalidDate = true; + DateTime oldDate = previousDate; + RefreshDateDisplay(); + if (DateSelected != null) DateSelected.Invoke(sender, new DateChangedEventArgs(oldDate, Date)); + previousDate = Date; + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Controls/SamDateTimePicker.cs b/SacsMobileMaui/Maui/Controls/SamDateTimePicker.cs new file mode 100644 index 0000000..52e731c --- /dev/null +++ b/SacsMobileMaui/Maui/Controls/SamDateTimePicker.cs @@ -0,0 +1,160 @@ +using Sarand.Net.Mobile.Maui.Layouts; +using Sarand.Net.Mobile.Maui.Views; +using Sarand.Net.Standard.Base.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Controls +{ + //======================================================================= + public class SamDateTimePicker : SamContentView + { + //------------------------------------------------------------------- + // Definitions. + // Control layout. + private SamStackLayout layoutControl = new SamStackLayout() { Orientation = StackOrientation.Horizontal }; + private SamDatePicker pickerDate = new SamDatePicker(); + private SamLabel labelTimePrefix = new SamLabel(); + private SamTimePicker pickerTime = new SamTimePicker(); + + //------------------------------------------------------------------- + // Data members. + + //------------------------------------------------------------------- + // Construction. + public SamDateTimePicker() + { + DefaultFontSize = pickerDate.FontSize; + + // Configure components. + Content = layoutControl; + layoutControl.Children.Add(pickerDate); + layoutControl.Children.Add(pickerTime); + + // Control events. + pickerDate.DateSelected += PickerDate_DateSelected; + pickerTime.TimeChanged += PickerTime_TimeChanged; + } + + //------------------------------------------------------------------- + // Properties. + public string DateFormat + { + get { return pickerDate.Format; } + set + { + if (pickerDate.Format.Equals(value)) return; + pickerDate.Format = value; + } + } + public DateTime MinimumDate + { + get { return pickerDate.MinimumDate; } + set { pickerDate.MinimumDate = value; } + } + public DateTime MaximumDate + { + get { return pickerDate.MaximumDate; } + set { pickerDate.MaximumDate = value; } + } + public string TimeFormat + { + get { return pickerTime.Format; } + set + { + if (pickerTime.Format.Equals(value)) return; + pickerTime.Format = value; + } + } + // Control value. + public DateTime DateTime + { + get { return pickerDate.Date.Date + pickerTime.Time; } + set + { + if (DateTime.CompareTo(value) == 0) return; + pickerDate.Date = value.Date; + pickerTime.Time = value - value.Date; + } + } + public String DateTimeDelim { get; set; } = " "; + public String FormattedDateTime { get { return pickerDate.FormattedDate + DateTimeDelim + pickerTime.FormattedTime; } } + // Styling. + public double DefaultFontSize { get; } + public double FontSize + { + get { return pickerDate.FontSize; } + set { if (pickerDate.FontSize == value) return; pickerDate.FontSize = value; pickerTime.FontSize = value; labelTimePrefix.FontSize = value; } + } + /// Amount of space between date and time pickers. + public double ControlSpacing + { + get { return layoutControl.Spacing; } + set { if (layoutControl.Spacing == value) return; layoutControl.Spacing = value; } + } + public String TimePickerPrefixText + { + get { return labelTimePrefix.Text; } + set { value = StringUtil.TrimAll(value); if (labelTimePrefix.Text.Equals(value)) return; labelTimePrefix.Text = value; ConfigureComponents(); } + } + + //------------------------------------------------------------------- + // C o n f i g u r e C o m p o n e n t s + //------------------------------------------------------------------- + public override void ConfigureComponents() + { + base.ConfigureComponents(); + + // Time Picker prefix label text. + if (!StringUtil.IsEmpty(TimePickerPrefixText)) + { + // Label has text - ensure label is in the layout. + if (!layoutControl.Children.Contains(labelTimePrefix)) + { + // Label will be inserted before the time picker. + int insertIdx = layoutControl.Children.IndexOf(pickerTime); + layoutControl.Children.Insert(insertIdx, labelTimePrefix); + } + } + else + { + // Blank label text - remove label from layout. + if (layoutControl.Children.Contains(labelTimePrefix)) + layoutControl.Children.Remove(labelTimePrefix); + } + } + + //------------------------------------------------------------------- + // C o n t r o l A c t i v i t y + //------------------------------------------------------------------- + public override void SetControlActivity() + { + base.SetControlActivity(); + } + public override void SetControlsReadOnly() + { + base.SetControlsReadOnly(); + } + + //------------------------------------------------------------------- + // C o n t r o l E v e n t s + //------------------------------------------------------------------- + private void PickerDate_DateSelected(object? sender, DateChangedEventArgs e) + { + if (DateSelected != null) DateSelected.Invoke(sender, e); + } + public event EventHandler? DateSelected; + //------------------------------------------------------------------- + private void PickerTime_TimeChanged(object? sender, SamTimePicker.TimeChangedEventArgs e) + { + if (TimeChanged != null) TimeChanged.Invoke(sender, e); + } + public event EventHandler? TimeChanged; + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Controls/SamEditor.cs b/SacsMobileMaui/Maui/Controls/SamEditor.cs new file mode 100644 index 0000000..7a83494 --- /dev/null +++ b/SacsMobileMaui/Maui/Controls/SamEditor.cs @@ -0,0 +1,84 @@ +using Sarand.Net.Mobile.Maui.App; +using Sarand.Net.Standard.Base.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Controls +{ + //======================================================================= + public class SamEditor : Editor + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + private bool trimTextOnCompletion = true; + private int NumberOfLinesPrevious = 0; + + //------------------------------------------------------------------- + // Construction. + public SamEditor() + { + DefaultFontSize = FontSize; + Text = ""; + TextChanged += SamEditor_TextChanged; + Completed += SamEditor_Completed; + } + + //------------------------------------------------------------------- + // Properties. + + public double DefaultFontSize { get; } + + public bool TrimText + { + get { return trimTextOnCompletion; } + set + { + if (trimTextOnCompletion == value) return; + trimTextOnCompletion = value; + } + } + + // Native behaviour modified by SamHandler. + public bool NativeNoBorder { get; set; } = Sam.Visuals.Form.Controls.NativeNoBorder; + public bool NativeNoUnderline { get; set; } = Sam.Visuals.Form.Controls.NativeNoUnderline; + public bool NativeBackgroundClear { get; set; } = Sam.Visuals.Form.Controls.NativeBackgroundClear; + + //------------------------------------------------------------------- + // C o n t r o l E v e n t s + //------------------------------------------------------------------- + // Key Press event is not supported directly in Xamarin. + // Requires O/S specific implementation. + // See: Sarand.LogisticsMgr.Mobile.Droid.Forms.Renderers.SlmEditorRenderer + public void OnKeyPress_Enter() + { + // Resize control based on entered text. + InvalidateMeasure(); + } + //------------------------------------------------------------------- + private void SamEditor_TextChanged(object? sender, TextChangedEventArgs e) + { + // If the number of lines of text has changed, resize the control. + int NumberOfLines = StringUtil.EmptyOnNull(Text).Split('\n').Length; + if (NumberOfLines != NumberOfLinesPrevious) + // Resize control based on entered text. + InvalidateMeasure(); + NumberOfLinesPrevious = NumberOfLines; + } + private void SamEditor_Completed(object? sender, EventArgs e) + { + if (trimTextOnCompletion) + Text = Text.Trim(); + // Resize control based on entered text. + InvalidateMeasure(); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Controls/SamEntry.cs b/SacsMobileMaui/Maui/Controls/SamEntry.cs new file mode 100644 index 0000000..2738565 --- /dev/null +++ b/SacsMobileMaui/Maui/Controls/SamEntry.cs @@ -0,0 +1,167 @@ +using Sarand.Net.Mobile.Maui.App; +using Sarand.Net.Standard.Base.App; +using Sarand.Net.Standard.Base.Utils; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Controls +{ + //======================================================================= + public class SamEntry : Entry + { + //------------------------------------------------------------------- + // Definitions. + public enum TextCaseType + { + Normal, + Upper, + Lower, + Title + } + + //------------------------------------------------------------------- + // Data members. + private bool trimTextOnCompletion = true; + private TextInfo textInfo = CultureInfo.CurrentCulture.TextInfo; + private TextCaseType textCase = TextCaseType.Normal; + private bool numericOnly = false; + private byte decimals = 0; + + //------------------------------------------------------------------- + // Construction. + public SamEntry() + { + DefaultFontSize = FontSize; + TextChanged += SamEntry_TextChanged; + Completed += SamEntry_Completed; + } + + //------------------------------------------------------------------- + // Properties. + public bool TrimText + { + get { return trimTextOnCompletion; } + set + { + if (trimTextOnCompletion == value) return; + trimTextOnCompletion = value; + } + } + /// + /// Whether to format text as it is entered. + /// NB This can lead to problems with the cursor position and typing doesn't give expected results. + /// Default: False. + /// + public bool FormatTextOnChange { get; set; } = false; + public double DefaultFontSize { get; } + public TextCaseType TextCase + { + get { return textCase; } + set + { + if (textCase == value) return; + textCase = value; + FormatText(); + } + } + public bool NumericOnly + { + get { return numericOnly; } + set + { + if (numericOnly == value) return; + numericOnly = value; + if (numericOnly) + HorizontalTextAlignment = TextAlignment.End; + Keyboard = Keyboard.Numeric; + FormatText(); + } + } + public byte Decimals + { + get { return decimals; } + set + { + if (numericOnly && decimals == value) return; + numericOnly = true; + HorizontalTextAlignment = TextAlignment.End; + decimals = value; + Keyboard = Keyboard.Numeric; + FormatText(); + } + } + + // Native behaviour modified by SamHandler. + public bool NativeNoBorder { get; set; } = Sam.Visuals.Form.Controls.NativeNoBorder; + public bool NativeNoUnderline { get; set; } = Sam.Visuals.Form.Controls.NativeNoUnderline; + public bool NativeBackgroundClear { get; set; } = Sam.Visuals.Form.Controls.NativeBackgroundClear; + + //------------------------------------------------------------------- + // F o r m a t T e x t + //------------------------------------------------------------------- + private void FormatText(bool trimText = false) + { + String fn = GetType().Name + ".FormatText"; + String originalText = Text; + String formattedText = originalText; + if (StringUtil.IsEmpty(formattedText)) return; + if (trimText) + formattedText = StringUtil.TrimAll(formattedText); + + if (numericOnly) + { + if (decimals > 0) + { + decimal value = StringUtil.ToDecimal(formattedText); + if (value != 0.0m) + formattedText = value.ToString("N" + decimals); + else if (!formattedText.Equals("0")) + formattedText = ""; + } + else + { + long value = StringUtil.ToLong(formattedText); + if (value != 0) + formattedText = value.ToString(); + else if (!formattedText.Equals("0")) + formattedText = ""; + } + } + else + { + if (textCase == TextCaseType.Upper) + formattedText = textInfo.ToUpper(formattedText); + else if (textCase == TextCaseType.Lower) + formattedText = textInfo.ToLower(formattedText); + else if (textCase == TextCaseType.Title) + formattedText = + StringUtil.ToTitleCase(formattedText, textInfo); + } + + if (!originalText.Equals(formattedText)) + { + SaLogger.Debug(fn + " Text: " + originalText + ". Formatted: " + formattedText); + Text = formattedText; + } + } + + //------------------------------------------------------------------- + // C o n t r o l E v e n t s + //------------------------------------------------------------------- + private void SamEntry_TextChanged(object? sender, TextChangedEventArgs e) + { + if (FormatTextOnChange) FormatText(); + } + private void SamEntry_Completed(object? sender, EventArgs e) + { + FormatText(trimTextOnCompletion); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Controls/SamImageButton.cs b/SacsMobileMaui/Maui/Controls/SamImageButton.cs new file mode 100644 index 0000000..2ee174f --- /dev/null +++ b/SacsMobileMaui/Maui/Controls/SamImageButton.cs @@ -0,0 +1,40 @@ +using Sarand.Net.Standard.Base.App; +using Sarand.Net.Standard.Base.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Controls +{ + //======================================================================= + public class SamImageButton : ImageButton + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + + //------------------------------------------------------------------- + // Construction. + public SamImageButton() + { + //Clicked += Button_Clicked; + } + + //------------------------------------------------------------------- + // Properties. + + //------------------------------------------------------------------- + // Events. + protected virtual void Button_Clicked(object? sender, EventArgs e) + { + SaLogger.Info(SysUtil.Fn + " Button clicked."); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Controls/SamLabel.cs b/SacsMobileMaui/Maui/Controls/SamLabel.cs new file mode 100644 index 0000000..ec1eb24 --- /dev/null +++ b/SacsMobileMaui/Maui/Controls/SamLabel.cs @@ -0,0 +1,78 @@ +using Sarand.Net.Standard.Base.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Controls +{ + //======================================================================= + public class SamLabel : Label + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + private double fontSize; + private double fontSizeProportion = 1.0; + + //------------------------------------------------------------------- + // Construction. + public SamLabel() + { + fontSize = base.FontSize; + FontSizeDefault = fontSize; + Text = ""; + } + + //------------------------------------------------------------------- + // Properties. + + /// Default (initial) font size. + public double FontSizeDefault { get; private set; } + + public new double FontSize + { + get { return fontSize; } + set { fontSize = value; base.FontSize = fontSize * fontSizeProportion; } + } + + /// Font size proportion. + public double FontSizeProportion + { + get { return fontSizeProportion; } + set { fontSizeProportion = value; base.FontSize = fontSize * fontSizeProportion; } + } + + //------------------------------------------------------------------- + // Control events. + + //------------------------------------------------------------------- + // View events. + + protected override void OnPropertyChanging([CallerMemberName] string propertyName = "") + { + base.OnPropertyChanging(propertyName); + if (propertyName.EqualsCI("FontSize")) + { + } + } + + protected override void OnPropertyChanged([CallerMemberName] string propertyName = "") + { + base.OnPropertyChanged(propertyName); + if (propertyName.EqualsCI("FontSize")) + { + if (FontSizeDefault <= 0) + FontSizeDefault = base.FontSize; + fontSize = base.FontSize; + } + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Controls/SamPicker.cs b/SacsMobileMaui/Maui/Controls/SamPicker.cs new file mode 100644 index 0000000..2481afe --- /dev/null +++ b/SacsMobileMaui/Maui/Controls/SamPicker.cs @@ -0,0 +1,178 @@ +using Sarand.Net.Mobile.Maui.App; +using Sarand.Net.Standard.Base.Bus; +using Sarand.Net.Standard.Base.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Controls +{ + //======================================================================= + public class SamPicker : Picker + { + //------------------------------------------------------------------- + // Definitions. + public class SamPickerItem + { + public SysId Id { get; set; } = new SysId(); + public String Code { get; set; } = ""; + public String Caption { get; set; } = ""; + public Object? Object { get; set; } + public override string ToString() + { + return Caption; + } + } + + //------------------------------------------------------------------- + // Data members. + private readonly List pickerItems = new List(); + + //------------------------------------------------------------------- + // Construction. + public SamPicker() + { + DefaultFontSize = FontSize; + } + + //------------------------------------------------------------------- + // Properties. + + public double DefaultFontSize { get; } + public bool BeingPopulated { get; protected set; } = false; + + // Native behaviour modified by SamHandler. + public bool NativeNoBorder { get; set; } = Sam.Visuals.Form.Controls.NativeNoBorder; + public bool NativeNoUnderline { get; set; } = Sam.Visuals.Form.Controls.NativeNoUnderline; + public bool NativeBackgroundClear { get; set; } = Sam.Visuals.Form.Controls.NativeBackgroundClear; + + //------------------------------------------------------------------- + // P o p u l a t e I t e m s + //------------------------------------------------------------------- + /// + /// Does the list contain an item with the same Id. + /// NB Invalid Id values are matched. + /// + public bool ContainsItemId(SysId id) + { + return pickerItems.Exists(item => SysId.ToInt(item.Id) == SysId.ToInt(id)); + } + /// + /// Does the list contain an item with the same code. + /// NB Codes are case-insensitive. + /// + public bool ContainsItemCode(String code) + { + return pickerItems.Exists(item => item.Code.EqualsCI(code)); + } + //------------------------------------------------------------------- + /// Remove all items from the picker. + public void ClearItems() + { + Items.Clear(); + ItemsSource = null; + pickerItems.Clear(); + } + /// Replace existing picker item list. + public void SetItems(List pickerItems) + { + ClearItems(); + this.pickerItems.AddRange(pickerItems); + RefreshPickerItems(); + } + //------------------------------------------------------------------- + /// + /// Add an item identified by a SysId value. + /// NB Fails if an item already exists with the same id. + /// + public bool AddItem(SysId id, String caption) + { + if (ContainsItemId(id)) return false; + pickerItems.Add(new SamPickerItem() { Id = id, Caption = caption }); + RefreshPickerItems(); + return ContainsItemId(id); + } + /// + /// Add an item identified by a code value. + /// NB Fails if an item already exists with the same case-insensitive code. + /// + public bool AddItem(String code, String caption) + { + if (ContainsItemCode(code)) return false; + pickerItems.Add(new SamPickerItem() { Code = code, Caption = caption }); + RefreshPickerItems(); + return ContainsItemCode(code); + } + //------------------------------------------------------------------- + private void RefreshPickerItems() + { + //SetBinding(Picker.ItemsSourceProperty, BindableProperty.Create()); + //ItemDisplayBinding = new Binding("Caption"); + // Picker items doesn't automatically keep up to date with teh ItemsSource list. + // So clear it and reset to force the refresh. + ItemsSource = null; + ItemsSource = pickerItems; + } + + //------------------------------------------------------------------- + // I t e m S e l e c t i o n + //------------------------------------------------------------------- + public SamPickerItem? SelectedPickerItem + { + get + { + object selectedItem = SelectedItem; + if (selectedItem == null || !(selectedItem is SamPickerItem)) return null; + return (selectedItem as SamPickerItem); + } + set + { + if (SelectedPickerItem == value) return; + if (ItemsSource == null || !ItemsSource.Contains(value)) return; + base.SelectedItem = value; + } + } + public SysId SelectedItemId + { + get + { + SamPickerItem? selectedPickerItem = SelectedPickerItem; + return selectedPickerItem?.Id ?? new SysId(); + } + set + { + SelectedPickerItem = pickerItems.Find(item => item.Id.Equals(value)); + } + } + public String SelectedItemCode + { + get + { + SamPickerItem? selectedPickerItem = SelectedPickerItem; + return selectedPickerItem?.Code ?? ""; + } + set + { + SelectedPickerItem = pickerItems.Find(item => item.Code.EqualsCI(value)); + } + } + + //------------------------------------------------------------------- + // C o n t r o l E v e n t s + //------------------------------------------------------------------- + // Picker population completed. + public class PopulatedEventArgs : EventArgs { } + public delegate void PopulatedEventHandler(object? sender, PopulatedEventArgs e); + /// Picker population completed event handler. + public event PopulatedEventHandler? Populated; + protected void InvokePopulatedEvent() + { + if (Populated != null) Populated.Invoke(this, new PopulatedEventArgs() { }); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Controls/SamTabControl.cs b/SacsMobileMaui/Maui/Controls/SamTabControl.cs new file mode 100644 index 0000000..29a2841 --- /dev/null +++ b/SacsMobileMaui/Maui/Controls/SamTabControl.cs @@ -0,0 +1,193 @@ +using Microsoft.Maui; +using Microsoft.Maui.Layouts; +using Sarand.Net.Mobile.Maui.Layouts; +using Sarand.Net.Mobile.Maui.Panels; +using Sarand.Net.Mobile.Maui.Views; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Controls +{ + //======================================================================= + public class SamTabControl : ContentView + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + private readonly List tabPanels = new List(); + private short currentTabIdx = -1; + // Main layout to host header and body. + private SamStackLayout mainLayout = new SamStackLayout() { Orientation = StackOrientation.Vertical }; + // Header layout - horizontal row. + private SamFlexLayout headerPanel = new SamFlexLayout() { Direction = FlexDirection.Row, AlignItems = FlexAlignItems.Center, JustifyContent = FlexJustify.Start, HorizontalOptions = LayoutOptions.Start }; + // Body - Content view to host tab panel. + private SamContentView bodyPanel = new SamContentView(); + + //------------------------------------------------------------------- + // Construction. + public SamTabControl() + { + // Main layout - vertical stack with two rows. + // 1. Header - tab panel captions. + // 2. Body - current tab panel. + VerticalOptions = LayoutOptions.FillAndExpand; + //BackgroundColor = Color.LightSkyBlue; + mainLayout.VerticalOptions = LayoutOptions.FillAndExpand; + mainLayout.Spacing = 2.0; + Content = mainLayout; + + // Header panel - tab captions. + //headerPanel.HorizontalOptions = LayoutOptions.Fill; + mainLayout.Children.Add(headerPanel); + + // Default label font size. + DefaultHeaderFontSize = new Label().FontSize; + HeaderFontSize = DefaultHeaderFontSize; + + // Body panel. + bodyPanel.HorizontalOptions = LayoutOptions.Fill; + bodyPanel.VerticalOptions = LayoutOptions.FillAndExpand; + bodyPanel.BackgroundColor = Colors.LightYellow; + mainLayout.Children.Add(bodyPanel); + } + + //------------------------------------------------------------------- + // Properties. + // Header. + public Color HeaderBackgroundColor { get { return headerPanel.BackgroundColor; } set { headerPanel.BackgroundColor = value; } } + public Color CaptionBackgroundColor { get; set; } = Colors.Transparent; + public double DefaultHeaderFontSize { get; } + public double HeaderFontSize { get; set; } + public double HeaderMarginBottom + { + get { return mainLayout.Spacing; } + set { if (mainLayout.Spacing == value) return; mainLayout.Spacing = value; } + } + public Thickness HeaderPadding + { + get { return mainLayout.Padding; } + set { if (mainLayout.Padding == value) return; mainLayout.Padding = value; } + } + public Thickness HeaderCaptionPadding { get; set; } = new Thickness(12.0, 4.0); + public double HeaderCaptionSpacing { get; set; } = 4.0; + // Tab panels. + public Color BodyBackgroundColor { get { return bodyPanel.BackgroundColor; } set { bodyPanel.BackgroundColor = value; } } + public int PanelCount { get { return tabPanels.Count; } } + public short TabPanelIndex + { + get { return currentTabIdx; } + set { ChangeTabPanel(value); } + } + + //------------------------------------------------------------------- + // T a b P a n e l s + //------------------------------------------------------------------- + public void ClearPanels() + { + tabPanels.Clear(); + RefreshLayout(); + } + public void AddPanel(String caption, SamContentView panel) + { + AddPanel(new SamTabPanel(caption, panel)); + } + public void AddPanel(SamTabPanel tabPanel) + { + AddPanels(new List() { tabPanel }); + } + public void AddPanels(IEnumerable tabPanels) + { + this.tabPanels.AddRange(tabPanels); + RefreshLayout(); + } + + //------------------------------------------------------------------- + // R e f r e s h L a y o u t + //------------------------------------------------------------------- + private void RefreshLayout() + { + // Clear existing components. + headerPanel.Children.Clear(); + bodyPanel.Content = null; + + // Add each Tab panel in turn. + for (short tabPanelIdx = 0; tabPanelIdx < tabPanels.Count; tabPanelIdx++) + { + short tabPanelIdx_Local = tabPanelIdx; // Loop closure. + SamTabPanel tabPanel = tabPanels[tabPanelIdx]; + + // Header caption. + SamContentView captionPanel = new SamContentView() + { + Padding = HeaderCaptionPadding, + BackgroundColor = CaptionBackgroundColor, + HorizontalOptions = LayoutOptions.FillAndExpand, + VerticalOptions = LayoutOptions.FillAndExpand + }; + if (tabPanelIdx > 0) + captionPanel.Margin = new Thickness(HeaderCaptionSpacing, 0, 0, 0); + SamLabel captionLabel = new SamLabel() + { + Text = tabPanel.Caption, + FontSize = HeaderFontSize + }; + captionPanel.Content = captionLabel; + headerPanel.Children.Add(captionPanel); + + // Tap Gesture. + var tapGestureRecognizer = new TapGestureRecognizer(); + tapGestureRecognizer.Tapped += (s, e) => { ChangeTabPanel(tabPanelIdx_Local); }; + captionPanel.GestureRecognizers.Add(tapGestureRecognizer); + } + // Current tab retains previous value if still valid (in panel range), + // is restricted to the range 0 to number of panels - 1 if there are panels, + // or -1 if no panels. + currentTabIdx = (short)(tabPanels.Count > 0 ? Math.Max(0, Math.Min(tabPanels.Count - 1, currentTabIdx)) : -1); + if (tabPanels.Count > 0) + ChangeTabPanel(currentTabIdx); + } + + //------------------------------------------------------------------- + // C h a n g e T a b P a n e l + //------------------------------------------------------------------- + private void ChangeTabPanel(short tabPanelIdx) + { + // Validate requested panel index. + if (tabPanelIdx < 0 || tabPanelIdx >= tabPanels.Count) + throw new IndexOutOfRangeException("Tab panel index must be between 0 & " + (tabPanels.Count - 1) + ". Supplied value: " + tabPanelIdx); + + // Highlight selected tab panel header caption. + for (short headerPanelIdx = 0; headerPanelIdx < headerPanel.Children.Count; headerPanelIdx++) + { + // View. + View? headerPanelView = headerPanel.Children[headerPanelIdx] as View; + // Label. + Label? headerPanelLabel = (headerPanelView as Label); + if (headerPanelLabel == null && headerPanelView is ContentView) + headerPanelLabel = ((ContentView)headerPanelView).Content as Label; + if (headerPanelLabel != null) + { + if (headerPanelIdx == tabPanelIdx) + headerPanelLabel.FontAttributes = FontAttributes.Bold; + else headerPanelLabel.FontAttributes = FontAttributes.None; + } + } + + // Display selected tab panel. + bodyPanel.Content = tabPanels[tabPanelIdx]; + currentTabIdx = tabPanelIdx; + } + + //------------------------------------------------------------------- + // C o n t r o l E v e n t s + //------------------------------------------------------------------- + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Controls/SamTimePicker.cs b/SacsMobileMaui/Maui/Controls/SamTimePicker.cs new file mode 100644 index 0000000..6718681 --- /dev/null +++ b/SacsMobileMaui/Maui/Controls/SamTimePicker.cs @@ -0,0 +1,53 @@ +using Sarand.Net.Standard.Base.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Controls +{ + //======================================================================= + public class SamTimePicker : TimePicker + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + + //------------------------------------------------------------------- + // Construction. + public SamTimePicker() + { + DefaultFontSize = FontSize; + Format = "HH:mm"; + } + + //------------------------------------------------------------------- + // Properties. + public String FormattedTime { get { return DateUtil.Format(DateTime.Today + Time, Format); } } + // Styling. + public double DefaultFontSize { get; } + + //------------------------------------------------------------------- + // C o n t r o l E v e n t s + //------------------------------------------------------------------- + public class TimeChangedEventArgs : EventArgs { }; + public event EventHandler? TimeChanged; + protected override void OnPropertyChanged([CallerMemberName] string propertyName = "") + { + if (propertyName.EqualsCI(TimePicker.TimeProperty.PropertyName)) + { + base.OnPropertyChanged(propertyName); + if (TimeChanged != null) TimeChanged.Invoke(this, new TimeChangedEventArgs()); + return; + } + base.OnPropertyChanged(propertyName); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Controls/SamWebView.cs b/SacsMobileMaui/Maui/Controls/SamWebView.cs new file mode 100644 index 0000000..cedb4f1 --- /dev/null +++ b/SacsMobileMaui/Maui/Controls/SamWebView.cs @@ -0,0 +1,103 @@ +using Sarand.Net.Standard.Base.App; +using Sarand.Net.Standard.Base.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Controls +{ + //======================================================================= + public class SamWebView : WebView + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + public String html = ""; + private HtmlWebViewSource htmlSource; + private UrlWebViewSource aboutBlankSource = new UrlWebViewSource() { Url = "about:blank" }; + // Managers. + + //------------------------------------------------------------------- + // Construction. + public SamWebView() + { + // Events. + Navigating += WebView_Navigating; + Navigated += WebView_Navigated; + + // HTML source. + htmlSource = new HtmlWebViewSource() { Html = html }; + Source = aboutBlankSource; + } + + //------------------------------------------------------------------- + // Properties. + // HTML Panel. + public static String AppActionPrefix => "App:"; + public String Html + { + get { return html; } + set + { + Source = aboutBlankSource; + htmlSource.Html = null; + html = value; + htmlSource.Html = html; + Source = htmlSource; + } + } + + //------------------------------------------------------------------- + // N a v i g a t i o n + //------------------------------------------------------------------- + public class AppNavigatingEventArgs : EventArgs + { + public AppNavigatingEventArgs(String appAction) + { + this.AppAction = appAction; + } + public String AppAction { get; } + } + public delegate void AppNavigatingEventHandler(object? sender, AppNavigatingEventArgs e); + public event AppNavigatingEventHandler? AppNavigating; + private void OnAppNavigating(String appAction) + { + if (AppNavigating != null) AppNavigating.Invoke(this, new AppNavigatingEventArgs(appAction)); + } + private String GetAppAction(String location) + { + if (!location.StartsWithCI(AppActionPrefix)) return ""; + return location.Right(location.Length - AppActionPrefix.Length); + } + + //------------------------------------------------------------------- + // C o n t r o l E v e n t s + //------------------------------------------------------------------- + private void WebView_Navigating(object? sender, WebNavigatingEventArgs e) + { + String appAction = GetAppAction(e.Url); + SaLogger.Debug("SamWebView_Navigating URL: " + e.Url + ". App action: " + appAction); + if (!StringUtil.IsEmpty(appAction)) + { + e.Cancel = true; + OnAppNavigating(appAction); + } + } + private void WebView_Navigated(object? sender, WebNavigatedEventArgs e) + { + SaLogger.Debug("SamWebView_Navigated URL: " + e.Url); + String appAction = GetAppAction(e.Url); + if (!StringUtil.IsEmpty(appAction)) + { + Source = htmlSource; + } + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Handlers/SamFormHandler.cs b/SacsMobileMaui/Maui/Handlers/SamFormHandler.cs new file mode 100644 index 0000000..433fdca --- /dev/null +++ b/SacsMobileMaui/Maui/Handlers/SamFormHandler.cs @@ -0,0 +1,139 @@ +#if ANDROID +using Microsoft.Maui.Controls.Compatibility.Platform.Android; +#endif +using Sarand.Net.Mobile.Maui.Controls; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Handlers +{ + //======================================================================== + // Ref. https://dev.to/vhugogarcia/remove-entry-and-picker-borders-in-net-maui-2pk2 + // Ref. https://github.com/dotnet/maui/issues/7906 + public static class SamFormHandler + { + //-------------------------------------------------------------------- + // Definitions. + + //-------------------------------------------------------------------- + /// + /// Remove borders around entry and picker controls. + /// Also make background transparent. + /// + public static void AssignControlHandlers() + { + //--------------------------------------------------------------- + // Entry handler. + Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("SamEntryHandler", (handler, view) => + { + if ((view as SamEntry)?.NativeNoBorder ?? false) + { +#if ANDROID + handler.PlatformView.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid()); +#elif IOS || MACCATALYST + handler.PlatformView.Layer.BorderWidth = 0; + handler.PlatformView.BorderStyle = UIKit.UITextBorderStyle.None; +#elif WINDOWS + handler.PlatformView.BorderThickness = new Microsoft.UI.Xaml.Thickness() { Bottom = 0, Top = 0, Left = 0, Right = 0, }; +#endif + } + if ((view as SamEntry)?.NativeNoUnderline ?? false) + { +#if ANDROID + handler.PlatformView.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid()); +#elif IOS || MACCATALYST +#elif WINDOWS +#endif + } + if ((view as SamEntry)?.NativeBackgroundClear ?? false) + { +#if ANDROID + handler.PlatformView.Background = null; + handler.PlatformView.SetBackgroundColor(Android.Graphics.Color.Transparent); +#elif IOS || MACCATALYST + handler.PlatformView.BackgroundColor = UIKit.UIColor.Clear; +#elif WINDOWS +#endif + } + }); + + //--------------------------------------------------------------- + // Editor handler. + Microsoft.Maui.Handlers.EditorHandler.Mapper.AppendToMapping("SamEditorHandler", (handler, view) => + { + if ((view as SamEditor)?.NativeNoBorder ?? false) + { +#if ANDROID + handler.PlatformView.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid()); +#elif IOS || MACCATALYST + handler.PlatformView.Layer.BorderWidth = 0; + //handler.PlatformView.BorderStyle = UIKit.UITextViewBorderStyle.None; +#elif WINDOWS + handler.PlatformView.BorderThickness = new Microsoft.UI.Xaml.Thickness() { Bottom = 0, Top = 0, Left = 0, Right = 0, }; +#endif + } + if ((view as SamEntry)?.NativeNoUnderline ?? false) + { +#if ANDROID + handler.PlatformView.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid()); +#elif IOS || MACCATALYST +#elif WINDOWS +#endif + } + if ((view as SamEntry)?.NativeBackgroundClear ?? false) + { +#if ANDROID + handler.PlatformView.Background = null; + handler.PlatformView.SetBackgroundColor(Android.Graphics.Color.Transparent); +#elif IOS || MACCATALYST + handler.PlatformView.BackgroundColor = UIKit.UIColor.Clear; +#elif WINDOWS +#endif + } + }); + + //--------------------------------------------------------------- + // Picker handler. + Microsoft.Maui.Handlers.PickerHandler.Mapper.AppendToMapping("Borderless", (handler, view) => + { + if ((view as SamEditor)?.NativeNoBorder ?? false) + { +#if ANDROID + handler.PlatformView.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid()); +#elif IOS || MACCATALYST + handler.PlatformView.Layer.BorderWidth = 0; + handler.PlatformView.BorderStyle = UIKit.UITextBorderStyle.None; +#elif WINDOWS + handler.PlatformView.BorderThickness = new Microsoft.UI.Xaml.Thickness() { Bottom = 0, Top = 0, Left = 0, Right = 0, }; +#endif + } + if ((view as SamEntry)?.NativeNoUnderline ?? false) + { +#if ANDROID + handler.PlatformView.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid()); +#elif IOS || MACCATALYST +#elif WINDOWS +#endif + } + if ((view as SamEntry)?.NativeBackgroundClear ?? false) + { +#if ANDROID + handler.PlatformView.Background = null; + handler.PlatformView.SetBackgroundColor(Android.Graphics.Color.Transparent); +#elif IOS || MACCATALYST + handler.PlatformView.BackgroundColor = UIKit.UIColor.Clear; +#elif WINDOWS +#endif + } + }); + + //--------------------------------------------------------------- + } + + //-------------------------------------------------------------------- + } + //======================================================================== +} diff --git a/SacsMobileMaui/Maui/Layouts/SamAbsoluteLayout.cs b/SacsMobileMaui/Maui/Layouts/SamAbsoluteLayout.cs new file mode 100644 index 0000000..6b6b6b2 --- /dev/null +++ b/SacsMobileMaui/Maui/Layouts/SamAbsoluteLayout.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Layouts +{ + //======================================================================= + public class SamAbsoluteLayout : AbsoluteLayout + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + + //------------------------------------------------------------------- + // Construction. + public SamAbsoluteLayout() + { + } + + //------------------------------------------------------------------- + // Properties. + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Layouts/SamFlexLayout.cs b/SacsMobileMaui/Maui/Layouts/SamFlexLayout.cs new file mode 100644 index 0000000..8b8ba34 --- /dev/null +++ b/SacsMobileMaui/Maui/Layouts/SamFlexLayout.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Layouts +{ + //======================================================================= + public class SamFlexLayout : FlexLayout + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + + //------------------------------------------------------------------- + // Construction. + public SamFlexLayout() + { + } + + //------------------------------------------------------------------- + // Properties. + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsStandardMob/Mobile/Forms/Layouts/SaxGrid.cs b/SacsMobileMaui/Maui/Layouts/SamGrid.cs similarity index 63% rename from SacsStandardMob/Mobile/Forms/Layouts/SaxGrid.cs rename to SacsMobileMaui/Maui/Layouts/SamGrid.cs index c87c97c..7935ffb 100644 --- a/SacsStandardMob/Mobile/Forms/Layouts/SaxGrid.cs +++ b/SacsMobileMaui/Maui/Layouts/SamGrid.cs @@ -1,13 +1,14 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Runtime.CompilerServices; using System.Text; -using Xamarin.Forms; +using System.Threading.Tasks; -namespace Sarand.Net.Standard.Mobile.Forms.Templates +namespace Sarand.Net.Mobile.Maui.Layouts { //======================================================================= - public class SaxGrid : Grid + public class SamGrid : Grid { //------------------------------------------------------------------- // Definitions. @@ -17,7 +18,7 @@ namespace Sarand.Net.Standard.Mobile.Forms.Templates //------------------------------------------------------------------- // Construction. - public SaxGrid () + public SamGrid() { } @@ -27,37 +28,36 @@ namespace Sarand.Net.Standard.Mobile.Forms.Templates //------------------------------------------------------------------- // G r i d E v e n t s //------------------------------------------------------------------- - protected override void OnParentSet () + protected override void OnParentSet() { base.OnParentSet(); } //------------------------------------------------------------------- - protected override void OnPropertyChanging ([CallerMemberName] string propertyName = null) + protected override void OnPropertyChanging([CallerMemberName] string propertyName = "") { base.OnPropertyChanging(propertyName); } - protected override void OnPropertyChanged ([CallerMemberName] string propertyName = null) + protected override void OnPropertyChanged([CallerMemberName] string propertyName = "") { base.OnPropertyChanged(propertyName); } //------------------------------------------------------------------- - protected override void OnAdded (View view) + protected override void OnAdd(int index, IView view) { - base.OnAdded(view); + base.OnAdd(index, view); } - protected override void OnChildAdded (Element child) + protected override void OnChildAdded(Element child) { base.OnChildAdded(child); } //------------------------------------------------------------------- - protected override void OnRemoved (View view) + protected override void OnRemove(int index, IView view) { - base.OnRemoved(view); + base.OnRemove(index, view); } - [Obsolete("OnChildRemoved(Element) is obsolete as of version 4.8.0. Please use OnChildRemoved(Element, int) instead.")] - protected override void OnChildRemoved (Element child) + protected override void OnChildRemoved(Element child, int oldLogicalIndex) { - base.OnChildRemoved(child); + base.OnChildRemoved(child, oldLogicalIndex); } //------------------------------------------------------------------- diff --git a/SacsMobileMaui/Maui/Layouts/SamStackLayout.cs b/SacsMobileMaui/Maui/Layouts/SamStackLayout.cs new file mode 100644 index 0000000..b1aea8b --- /dev/null +++ b/SacsMobileMaui/Maui/Layouts/SamStackLayout.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Layouts +{ + //======================================================================= + public class SamStackLayout : StackLayout + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + + //------------------------------------------------------------------- + // Construction. + public SamStackLayout() + { + } + + //------------------------------------------------------------------- + // Properties. + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Layouts/SamWrapLayout.cs b/SacsMobileMaui/Maui/Layouts/SamWrapLayout.cs new file mode 100644 index 0000000..3b03a75 --- /dev/null +++ b/SacsMobileMaui/Maui/Layouts/SamWrapLayout.cs @@ -0,0 +1,249 @@ +using Microsoft.Maui.Controls.Compatibility; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Layouts +{ + //======================================================================= + /// + /// Wrapping columnar layout - to achieve resposive behaviour. + /// Layout which performs wrapping on the boundaries. + /// Base Code -> https://forums.xamarin.com/discussion/comment/57486/#Comment_57486 + /// http://bit.ly/xf-custompanel + /// + //======================================================================= + public class SamWrapLayout : Layout + { + //------------------------------------------------------------------- + /// Horizontal spacing between elements. + public double SpacingX + { + get { return (double)GetValue(SpacingXProperty); } + set { SetValue(SpacingXProperty, value); } + } + public static BindableProperty SpacingXProperty = + BindableProperty.Create( + nameof(SpacingX), + typeof(double), + typeof(SamWrapLayout), + default(double), + defaultBindingMode: BindingMode.OneWay, + propertyChanged: (bindable, oldvalue, newvalue) => ((SamWrapLayout)bindable).InvalidateMeasure() + ); + /// Vertical spacing between elements. + public double SpacingY + { + get { return (double)GetValue(SpacingYProperty); } + set { SetValue(SpacingYProperty, value); } + } + public static BindableProperty SpacingYProperty = + BindableProperty.Create( + nameof(SpacingY), + typeof(double), + typeof(SamWrapLayout), + default(double), + defaultBindingMode: BindingMode.OneWay, + propertyChanged: (bindable, oldvalue, newvalue) => ((SamWrapLayout)bindable).InvalidateMeasure() + ); + + //------------------------------------------------------------------- + /// Number of uniform columns in each row. + public int UniformColumns + { + get { return (int)GetValue(UniformColumnsProperty); } + set { SetValue(UniformColumnsProperty, value); } + } + public static BindableProperty UniformColumnsProperty = + BindableProperty.Create( + nameof(UniformColumns), + typeof(int), + typeof(SamWrapLayout), + default(int), + defaultBindingMode: BindingMode.OneWay, + propertyChanged: (bindable, oldvalue, newvalue) => ((SamWrapLayout)bindable).InvalidateMeasure() + ); + + //------------------------------------------------------------------- + /// Item height equals item width when UniformColums > 0 + public bool IsSquare + { + get { return (bool)GetValue(IsSquareProperty); } + set { SetValue(IsSquareProperty, value); } + } + public static BindableProperty IsSquareProperty = + BindableProperty.Create( + nameof(IsSquare), + typeof(bool), + typeof(SamWrapLayout), + false, + propertyChanged: (bindable, oldvalue, newvalue) => ((SamWrapLayout)bindable).InvalidateMeasure() + ); + + //------------------------------------------------------------------- + protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint) + { + if (WidthRequest > 0) + widthConstraint = Math.Min(widthConstraint, WidthRequest); + if (HeightRequest > 0) + heightConstraint = Math.Min(heightConstraint, HeightRequest); + + double internalWidth = double.IsPositiveInfinity(widthConstraint) ? double.PositiveInfinity : Math.Max(0, widthConstraint); + double internalHeight = double.IsPositiveInfinity(heightConstraint) ? double.PositiveInfinity : Math.Max(0, heightConstraint); + + if (double.IsPositiveInfinity(widthConstraint) && double.IsPositiveInfinity(heightConstraint)) + { + return new SizeRequest(Microsoft.Maui.Graphics.Size.Zero, Microsoft.Maui.Graphics.Size.Zero); + } + + return UniformColumns > 0 ? UniformMeasureAndLayout(internalWidth, internalHeight) : + VariableMeasureAndLayout(internalWidth, internalHeight); + + } + + //------------------------------------------------------------------- + protected override void LayoutChildren(double x, double y, double width, double height) + { + if (UniformColumns > 0) + UniformMeasureAndLayout(width, height, true, x, y); + else + VariableMeasureAndLayout(width, height, true, x, y); + } + + //------------------------------------------------------------------- + private SizeRequest UniformMeasureAndLayout + (double widthConstraint, double heightConstraint, bool doLayout = false, double x = 0, double y = 0) + { + double totalWidth = 0; + double totalHeight = 0; + double rowHeight = 0; + double minWidth = 0; + double minHeight = 0; + double xPos = x; + double yPos = y; + + totalWidth = widthConstraint; + var exceptedWidth = widthConstraint - (UniformColumns - 1) * SpacingX; //excepted spacing width + + var columnsSize = exceptedWidth / UniformColumns; + if (columnsSize < 1) + { + columnsSize = 1; + } + + foreach (var child in Children.Where(c => c.IsVisible)) + { + + var size = child.Measure(widthConstraint, heightConstraint); + var itemWidth = (double)columnsSize; + var itemHeight = size.Request.Height; + + if (IsSquare) + { + itemHeight = columnsSize; + } + + rowHeight = Math.Max(rowHeight, itemHeight + SpacingY); + + minHeight = Math.Max(minHeight, itemHeight); + minWidth = Math.Max(minWidth, itemWidth); + + if (doLayout) + { + var region = new Rect(xPos, yPos, itemWidth, itemHeight); + LayoutChildIntoBoundingRegion(child, region); + } + + xPos += itemWidth + SpacingX; + + if (xPos + columnsSize - x > widthConstraint) + { + xPos = x; + yPos += rowHeight; + totalHeight += rowHeight; + rowHeight = 0; + } + } + + totalHeight = Math.Max(totalHeight + rowHeight - SpacingY, 0); + + return new SizeRequest(new Microsoft.Maui.Graphics.Size(totalWidth, totalHeight), new Microsoft.Maui.Graphics.Size(minWidth, minHeight)); + } + + //------------------------------------------------------------------- + private SizeRequest VariableMeasureAndLayout + (double widthConstraint, double heightConstraint, bool doLayout = false, double x = 0, double y = 0) + { + double totalWidth = 0; + double totalHeight = 0; + double rowHeight = 0; + double rowWidth = 0; + double minWidth = 0; + double minHeight = 0; + double xPos = x; + double yPos = y; + + var visibleChildren = Children.Where(c => c.IsVisible).Select(c => new + { + child = c, + size = c.Measure(widthConstraint, heightConstraint) + }); + + var nextChildren = visibleChildren.Skip(1).ToList(); + nextChildren.Add(null); //make element count same + + var zipChildren = visibleChildren.Zip(nextChildren, (c, n) => new { current = c, next = n }); + + foreach (var childBlock in zipChildren) + { + var child = childBlock.current.child; + var size = childBlock.current.size; + var itemWidth = size.Request.Width; + var itemHeight = size.Request.Height; + + rowHeight = Math.Max(rowHeight, itemHeight + SpacingY); + rowWidth += itemWidth + SpacingX; + + minHeight = Math.Max(minHeight, itemHeight); + minWidth = Math.Max(minWidth, itemWidth); + + if (doLayout) + { + var region = new Rect(xPos, yPos, itemWidth, itemHeight); + LayoutChildIntoBoundingRegion(child, region); + } + + if (childBlock.next == null) + { + totalHeight += rowHeight; + totalWidth = Math.Max(totalWidth, rowWidth); + break; + } + + xPos += itemWidth + SpacingX; + var nextWitdh = childBlock.next.size.Request.Width; + + if (xPos + nextWitdh - x > widthConstraint) + { + xPos = x; + yPos += rowHeight; + totalHeight += rowHeight; + totalWidth = Math.Max(totalWidth, rowWidth); + rowHeight = 0; + rowWidth = 0; + } + } + + totalWidth = Math.Max(totalWidth - SpacingX, 0); + totalHeight = Math.Max(totalHeight - SpacingY, 0); + + return new SizeRequest(new Microsoft.Maui.Graphics.Size(totalWidth, totalHeight), new Microsoft.Maui.Graphics.Size(minWidth, minHeight)); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Pages/SamContentPage.cs b/SacsMobileMaui/Maui/Pages/SamContentPage.cs new file mode 100644 index 0000000..57a2f15 --- /dev/null +++ b/SacsMobileMaui/Maui/Pages/SamContentPage.cs @@ -0,0 +1,182 @@ +using Microsoft.Maui.Controls; +using Sarand.Net.Mobile.Maui.Views; +using Sarand.Net.Standard.Base.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Pages +{ + //======================================================================= + public abstract class SamContentPage : ContentPage + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + + //------------------------------------------------------------------- + // Construction. + public SamContentPage() + { + } + + //------------------------------------------------------------------- + // Properties. + public abstract String MessageTitleDefault { get; } + + //------------------------------------------------------------------- + // C o n f i g u r e C o m p o n e n t s + //------------------------------------------------------------------- + protected virtual void ConfigureComponents() + { + } + + protected virtual void ConfigureChildComponents() + { + // Configure child components. + if (Content != null) + { + ConfigureChildComponent(Content); + foreach (var descendent in Content.GetVisualTreeDescendants()) + { + View? childView = descendent as View; + if (childView != null) + ConfigureChildComponent(childView); + } + } + } + + private void ConfigureChildComponent(View view) + { + if (view is ISamView) + { + ISamView? samView = view as ISamView; + if (samView != null) + samView.ConfigureComponents(); + } + } + + //------------------------------------------------------------------- + // C o n t r o l A c t i v i t y + //------------------------------------------------------------------- + protected virtual void SetControlActivity() + { + SetControlsReadOnly(); + + // Child component control activity. + if (Content != null) + { + SetChildControlActivity(Content); + foreach (var descendent in Content.GetVisualTreeDescendants()) + { + View? childView = descendent as View; + if (childView != null) + SetChildControlActivity(childView); + } + } + } + private void SetChildControlActivity(View view) + { + if (view is ISamView) + { + ISamView? samView = view as ISamView; + if (samView != null) + samView.SetControlActivity(); + } + } + protected virtual void SetControlsReadOnly() + { + } + + //------------------------------------------------------------------- + // P o p u p M e s s a g e s + //------------------------------------------------------------------- + public enum AlertMode + { + OK, + Close, + } + public Task DisplayAlert(String message, AlertMode alertMode = AlertMode.OK) + { + String title = StringUtil.OnEmpty(Title, MessageTitleDefault); + String cancel = "OK"; + if (alertMode == AlertMode.Close) + cancel = "Close"; + return DisplayAlert(title, message, cancel); + } + public enum ConfirmMode + { + YesNo, + OkCancel + } + public async Task DisplayConfirm(String message, ConfirmMode confirmMode = ConfirmMode.OkCancel) + { + String title = StringUtil.OnEmpty(Title, MessageTitleDefault); + String accept = "Yes"; + String cancel = "No"; + if (confirmMode == ConfirmMode.OkCancel) + { + accept = "OK"; + cancel = "Cancel"; + } + return await DisplayAlert(title, message, accept, cancel); + } + + //------------------------------------------------------------------- + // P a g e E v e n t s + //------------------------------------------------------------------- + protected override void OnParentSet() + { + base.OnParentSet(); + } + + //------------------------------------------------------------------- + protected override void OnPropertyChanged([CallerMemberName] string propertyName = "") + { + base.OnPropertyChanged(propertyName); + } + + //------------------------------------------------------------------- + protected override void OnAppearing() + { + base.OnAppearing(); + ConfigureComponents(); + ConfigureChildComponents(); + } + + //------------------------------------------------------------------- + // Layout changes. + private bool inOnSizeAllocated = false; + protected override void OnSizeAllocated(double width, double height) + { + bool alreadyInOnSizeAllocated = inOnSizeAllocated; + inOnSizeAllocated = true; + base.OnSizeAllocated(width, height); + // Only configure components if this is the first entry to this event + // // to avoid iterative layout changes caused by components being configured. + if (!alreadyInOnSizeAllocated) + { + if (Width > 0 && Height > 0) + { + ConfigureComponents(); + ConfigureChildComponents(); + } + inOnSizeAllocated = false; + } + } + + //------------------------------------------------------------------- + protected override void OnDisappearing() + { + base.OnDisappearing(); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Panels/SamPanel.cs b/SacsMobileMaui/Maui/Panels/SamPanel.cs new file mode 100644 index 0000000..7bda81f --- /dev/null +++ b/SacsMobileMaui/Maui/Panels/SamPanel.cs @@ -0,0 +1,81 @@ +using Sarand.Net.Mobile.Maui.Views; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Panels +{ + //======================================================================= + public class SamPanel : SamContentView + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + + //------------------------------------------------------------------- + // Construction. + public SamPanel() + { + } + + //------------------------------------------------------------------- + // Properties. + + //------------------------------------------------------------------- + // C o n f i g u r e C o m p o n e n t s + //------------------------------------------------------------------- + public override void ConfigureComponents() + { + base.ConfigureComponents(); + } + + //------------------------------------------------------------------- + // C o n t r o l A c t i v i t y + //------------------------------------------------------------------- + public override void SetControlActivity() + { + } + public override void SetControlsReadOnly() + { + } + + //------------------------------------------------------------------- + // P a n e l E v e n t s + //------------------------------------------------------------------- + protected override void OnParentSet() + { + base.OnParentSet(); + } + //------------------------------------------------------------------- + protected override void OnPropertyChanging([CallerMemberName] string propertyName = "") + { + base.OnPropertyChanging(propertyName); + } + protected override void OnPropertyChanged([CallerMemberName] string propertyName = "") + { + base.OnPropertyChanged(propertyName); + } + //------------------------------------------------------------------- + protected override void OnChildAdded(Element child) + { + base.OnChildAdded(child); + } + protected override void OnChildRemoved(Element child, int oldLogicalIndex) + { + base.OnChildRemoved(child, oldLogicalIndex); + } + //------------------------------------------------------------------- + protected override void OnSizeAllocated(double width, double height) + { + base.OnSizeAllocated(width, height); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Panels/SamPanel_ItemFilter.cs b/SacsMobileMaui/Maui/Panels/SamPanel_ItemFilter.cs new file mode 100644 index 0000000..9f3904f --- /dev/null +++ b/SacsMobileMaui/Maui/Panels/SamPanel_ItemFilter.cs @@ -0,0 +1,169 @@ +using Sarand.Net.Mobile.Maui.Layouts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Panels +{ + //======================================================================= + public class SacsFilterPropertyType + { + public enum FilterMode { Text, DropDownList } + public SacsFilterPropertyType(int propertyType, String caption) + { + PropertyType = propertyType; + Caption = caption; + } + public int PropertyType { get; } + public String Caption { get; } + public FilterMode Mode { get; set; } = FilterMode.Text; + } + public class SamPanel_ItemFilter : SamWrapLayout + { + //------------------------------------------------------------------- + // Definitions. + public class Config + { + public List FilterPropertyTypes { get; } = new List(); + public ushort FiltersToDisplay { get; set; } = 2; + public int PropertyTypeWidth { get; set; } = 100; + public int PropertyValueWidth { get; set; } = 120; + } + + //------------------------------------------------------------------- + // Data members. + private Config config; + private SamPanel_ItemFilterProperty[] itemFilterProperties = new SamPanel_ItemFilterProperty[0]; + + //------------------------------------------------------------------- + // Construction. + public SamPanel_ItemFilter(Config config) + { + this.config = config; + InitialiseComponents(); + } + + //------------------------------------------------------------------- + // Properties. + public int FilterCount { get { return Math.Min(config.FiltersToDisplay, config.FilterPropertyTypes.Count); } } + + //------------------------------------------------------------------- + // Configure. + public void SetConfig(Config config) + { + this.config = config; + ConfigurePanel(); + } + + //------------------------------------------------------------------- + // P u b l i c I n t e r f a c e + //------------------------------------------------------------------- + public String GetFilterPropertyValue(int propertyType) + { + foreach (SamPanel_ItemFilterProperty propertyFilter in itemFilterProperties) + { + if (propertyFilter.SelectedPropertyType == propertyType) + return propertyFilter.PropertyValue; + } + return ""; + } + + //------------------------------------------------------------------- + // I n i t i a l i s e + //------------------------------------------------------------------- + private void InitialiseComponents() + { + // Styling. + SpacingX = 8.0; + SpacingY = 4.0; + BackgroundColor = Colors.Transparent; + + ConfigurePanel(); + } + + //------------------------------------------------------------------- + // C o n f i g u r e P a n e l + //------------------------------------------------------------------- + private void ConfigurePanel() + { + // Clear filter panels. + Children.Clear(); + + // Reconfigure fiter properties. + if (itemFilterProperties.Length != FilterCount) + { + // Create new set of filters and copy previous filters across up to required number. + SamPanel_ItemFilterProperty[] itemFilterPropertiesNew = new SamPanel_ItemFilterProperty[FilterCount]; + for (int filterIdx = 0; filterIdx < Math.Min(itemFilterProperties.Length, FilterCount); filterIdx++) + itemFilterPropertiesNew[filterIdx] = itemFilterProperties[filterIdx]; + for (int filterIdx = itemFilterProperties.Length; filterIdx < FilterCount; filterIdx++) + { + itemFilterPropertiesNew[filterIdx] = new SamPanel_ItemFilterProperty(new SamPanel_ItemFilterProperty.Config()); + itemFilterPropertiesNew[filterIdx].PropertyFilterChanged += SamPanel_ItemFilter_PropertyFilterChanged; + } + itemFilterProperties = itemFilterPropertiesNew; + } + + // Retrieve currently selected property types. + List selectedPropertyTypes = new List(); + for (int filterIdx = 0; filterIdx < FilterCount; filterIdx++) + { + int selectedPropertyType = itemFilterProperties[filterIdx].SelectedPropertyType; + if (selectedPropertyType >= 0 && !selectedPropertyTypes.Contains(selectedPropertyType)) + selectedPropertyTypes.Add(selectedPropertyType); + } + + // Configure filter panels. + for (int filterIdx = 0; filterIdx < FilterCount; filterIdx++) + { + SamPanel_ItemFilterProperty propertyPanel = itemFilterProperties[filterIdx]; + + // Determine the property types to display - remove property types selected in other panels. + List filterPropertyTypes = new List(config.FilterPropertyTypes); + filterPropertyTypes.RemoveAll(item => item.PropertyType != propertyPanel.SelectedPropertyType && selectedPropertyTypes.Contains(item.PropertyType)); + if (filterPropertyTypes.Count == 0) continue; + + SamPanel_ItemFilterProperty.Config propertyPanelConfig = new SamPanel_ItemFilterProperty.Config(); + propertyPanelConfig.FilterPropertyTypes.AddRange(filterPropertyTypes); + propertyPanelConfig.PropertyTypeWidth = config.PropertyTypeWidth; + propertyPanelConfig.PropertyValueWidth = config.PropertyValueWidth; + propertyPanel.SetConfig(propertyPanelConfig); + + // Include the selecetd type in the list of not already present. + int selectedPropertyType = propertyPanel.SelectedPropertyType; + if (selectedPropertyType >= 0 && !selectedPropertyTypes.Contains(selectedPropertyType)) + selectedPropertyTypes.Add(selectedPropertyType); + + // Add panel to the layout. + Children.Add(propertyPanel); + } + } + + //------------------------------------------------------------------- + // F i l t e r E v e n t s + //------------------------------------------------------------------- + public class FilterChangedEventArgs : EventArgs + { + public int PropertyType { get; set; } = -1; + } + public event EventHandler? FilterChanged; + private void FireFilterChangedEvent(int propertyType) + { + FilterChangedEventArgs filterChangedEventArgs = new FilterChangedEventArgs() + { + PropertyType = propertyType, + }; + if (FilterChanged != null) FilterChanged.Invoke(this, filterChangedEventArgs); + } + //------------------------------------------------------------------- + private void SamPanel_ItemFilter_PropertyFilterChanged(object? sender, SamPanel_ItemFilterProperty.PropertyFilterChangedEventArgs e) + { + FireFilterChangedEvent(e.PropertyType); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Panels/SamPanel_ItemFilterProperty.cs b/SacsMobileMaui/Maui/Panels/SamPanel_ItemFilterProperty.cs new file mode 100644 index 0000000..539e703 --- /dev/null +++ b/SacsMobileMaui/Maui/Panels/SamPanel_ItemFilterProperty.cs @@ -0,0 +1,174 @@ +using Sarand.Net.Mobile.Maui.Controls; +using Sarand.Net.Mobile.Maui.Layouts; +using Sarand.Net.Standard.Base.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Panels +{ + //======================================================================= + public class SamPanel_ItemFilterProperty : SamPanel + { + //------------------------------------------------------------------- + // Definitions. + public class Config + { + public List FilterPropertyTypes { get; } = new List(); + public GridLength Height { get; set; } = GridLength.Auto; + public int PropertyTypeWidth { get; set; } = 0; + public int PropertyValueWidth { get; set; } = 0; + } + + //------------------------------------------------------------------- + // Data members. + private Config config; + private SamGrid? grid; + private SamPicker pickerPropertyType = new SamPicker(); + private SamEntry entryPropertyValue = new SamEntry() { Text = "", HorizontalOptions = LayoutOptions.FillAndExpand }; + private SamPicker pickerPropertyValue = new SamPicker() { HorizontalOptions = LayoutOptions.FillAndExpand, IsVisible = false }; + + //------------------------------------------------------------------- + // Construction. + public SamPanel_ItemFilterProperty(Config config) + { + this.config = config; + InitialiseComponents(); + } + + //------------------------------------------------------------------- + // Properties. + public bool Initialising { get; set; } = true; + private SacsFilterPropertyType? SelectedProperty { get { return config.FilterPropertyTypes.Find(item => item.PropertyType == StringUtil.ToInt(pickerPropertyType.SelectedItemCode)); } } + public int SelectedPropertyType { get { return SelectedProperty?.PropertyType ?? -1; } } + public String PropertyValue + { + get + { + if (SelectedProperty?.Mode == SacsFilterPropertyType.FilterMode.DropDownList) + return pickerPropertyValue.SelectedItemCode; + return entryPropertyValue.Text; + } + } + + //------------------------------------------------------------------- + // Configure. + public void SetConfig(Config config) + { + this.config = config; + ConfigurePanel(); + } + + //------------------------------------------------------------------- + // I n i t i a l i s e + //------------------------------------------------------------------- + private void InitialiseComponents() + { + // Grid - property type picker followed by property value control. + grid = new SamGrid() + { + BackgroundColor = Colors.Transparent, + RowSpacing = 0, + ColumnSpacing = 4, + RowDefinitions = new RowDefinitionCollection() + { + // Single row. + new RowDefinition(){ Height = config.Height } + }, + ColumnDefinitions = new ColumnDefinitionCollection() + { + // Two columns - property type & value. + new ColumnDefinition(){ Width = config.PropertyTypeWidth > 0 ? config.PropertyTypeWidth : GridLength.Auto }, + new ColumnDefinition(){ Width = config.PropertyValueWidth > 0 ? config.PropertyValueWidth : GridLength.Auto } + } + }; + Content = grid; + + // Property type. + if (config.PropertyTypeWidth > 0) + pickerPropertyType.WidthRequest = config.PropertyTypeWidth; + grid.Add(pickerPropertyType, 0, 0); + pickerPropertyType.SelectedIndexChanged += PickerPropertyType_SelectedIndexChanged; + + // Property value. + if (config.PropertyValueWidth > 0) + entryPropertyValue.WidthRequest = config.PropertyValueWidth; + entryPropertyValue.TextChanged += EntryPropertyValue_TextChanged; + grid.Add(entryPropertyValue, 1, 0); + if (config.PropertyValueWidth > 0) + pickerPropertyValue.WidthRequest = config.PropertyValueWidth; + pickerPropertyValue.SelectedIndexChanged += PickerPropertyValue_SelectedIndexChanged; + grid.Add(pickerPropertyValue, 1, 0); + + ConfigurePanel(); + } + + //------------------------------------------------------------------- + // C o n f i g u r e P a n e l + //------------------------------------------------------------------- + private void ConfigurePanel() + { + Initialising = true; + + // Configure layout. + if (grid != null) + { + grid.ColumnDefinitions.Clear(); + grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = config.PropertyTypeWidth }); + grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = config.PropertyValueWidth }); + } + + // Make a note of the currently selected property type. + int selectedPropertyType = SelectedPropertyType; + pickerPropertyType.ClearItems(); + + // Populate list of property types. + foreach (SacsFilterPropertyType propertyType in config.FilterPropertyTypes) + { + pickerPropertyType.AddItem(propertyType.PropertyType.ToString(), propertyType.Caption); + } + pickerPropertyType.SelectedItemCode = selectedPropertyType.ToString(); + if (pickerPropertyType.SelectedIndex < 0 && pickerPropertyType.Items.Count > 0) + pickerPropertyType.SelectedIndex = 0; + + Initialising = false; + } + + //------------------------------------------------------------------- + // P r o p e r t y F i l t e r E v e n t s + //------------------------------------------------------------------- + public class PropertyFilterChangedEventArgs : EventArgs + { + public int PropertyType { get; set; } = -1; + } + public event EventHandler? PropertyFilterChanged; + private void FireFilterChangedEvent(int propertyType) + { + if (Initialising) return; + PropertyFilterChangedEventArgs filterChangedEventArgs = new PropertyFilterChangedEventArgs() + { + PropertyType = propertyType, + }; + if (PropertyFilterChanged != null) PropertyFilterChanged.Invoke(this, filterChangedEventArgs); + } + + //------------------------------------------------------------------- + private void PickerPropertyType_SelectedIndexChanged(object? sender, EventArgs e) + { + FireFilterChangedEvent(SelectedPropertyType); + } + private void EntryPropertyValue_TextChanged(object? sender, TextChangedEventArgs e) + { + FireFilterChangedEvent(SelectedPropertyType); + } + private void PickerPropertyValue_SelectedIndexChanged(object? sender, EventArgs e) + { + FireFilterChangedEvent(SelectedPropertyType); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Panels/SamPanel_ItemListHeader.cs b/SacsMobileMaui/Maui/Panels/SamPanel_ItemListHeader.cs new file mode 100644 index 0000000..a3083ae --- /dev/null +++ b/SacsMobileMaui/Maui/Panels/SamPanel_ItemListHeader.cs @@ -0,0 +1,286 @@ +using Sarand.Net.Mobile.Maui.Controls; +using Sarand.Net.Mobile.Maui.Layouts; +using Sarand.Net.Mobile.Maui.Utils; +using Sarand.Net.Mobile.Maui.Views; +using Sarand.Net.Standard.Base.Dbas; +using Sarand.Net.Standard.Base.Helpers; +using Sarand.Net.Standard.Base.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Panels +{ + //======================================================================= + public class SamPanel_ItemListHeader : SamPanel + { + //------------------------------------------------------------------- + // Definitions. + public class Config + { + public Thickness? Margin { get; set; } = new Thickness(0, 0, 0, 8); + public String Caption { get; set; } = ""; + public double HeaderBorderWidth { get; set; } = 4.0; + public float HeaderBorderRadius { get; set; } = 8.0f; + public Color HeaderBorderColor { get; set; } = Color.FromArgb("#808080"); + public Color HeaderBackgroundColor { get; set; } = Color.FromArgb("#F0F0F0"); + // Labels. + // Styling. + public double CaptionLabelFontSizeRatio { get; set; } = 1.0; + public double PagingLabelFontSizeRatio { get; set; } = 1.0; + public Thickness? LabelMargin { get; set; } = null; + // Paging controls. + public static int PagingButtonWidthMin { get; } = 40; + public static int PagingButtonWidthMax { get; } = 64; + public static int PagingButtonWidthDefault { get; } = PagingButtonWidthMin; + public int PagingButtonWidth { get; set; } = PagingButtonWidthDefault; + public static int PagingButtonHeightMin { get; } = 40; + public static int PagingButtonHeightMax { get; } = 64; + public static int PagingButtonHeightDefault { get; } = PagingButtonHeightMin; + public int PagingButtonHeight { get; set; } = PagingButtonHeightDefault; + // Filters. + public List FilterPropertyTypes { get; } = new List(); + public ushort FiltersToDisplay { get; set; } = 2; + } + + //------------------------------------------------------------------- + // Data members. + private Config config; + // Layout. + private SamFrame frame = new SamFrame(); + private SamStackLayout mainLayout = new SamStackLayout() { Orientation = StackOrientation.Vertical }; + // Header. + private SamWrapLayout headerLayout = new SamWrapLayout() { SpacingX = 8.0 }; + private SamContentView captionLabelView = new SamContentView(); + private SamLabel labelCaption = new SamLabel() { Text = "" }; + private double initialLabelFontSize = 0; + // Paging. + private class PagingData : DbQuery.Paging + { + public int TotalItems { get; set; } + public int TotalPages { get { return PageLength > 0 ? (int)Math.Ceiling((double)TotalItems / PageLength) : 0; } } + public override bool Paged { get { return base.Paged && TotalItems > 0; } } + } + private readonly PagingData paging = new PagingData(); + private SamStackLayout pagingStack = new SamStackLayout() { Orientation = StackOrientation.Horizontal }; + private SamLabel labelPaging = new SamLabel() { Text = "[Paging]" }; + private SamImageButton buttonPagingFirst = new SamImageButton() { WidthRequest = 32, HeightRequest = 32, Aspect = Aspect.AspectFit, Padding = new Thickness(2, 4), BackgroundColor = Colors.Transparent }; + private SamImageButton buttonPagingPrev = new SamImageButton() { WidthRequest = 32, HeightRequest = 32, Aspect = Aspect.AspectFit, Padding = new Thickness(2, 4), BackgroundColor = Colors.Transparent }; + private SamImageButton buttonPagingNext = new SamImageButton() { WidthRequest = 32, HeightRequest = 32, Aspect = Aspect.AspectFit, Padding = new Thickness(2, 4), BackgroundColor = Colors.Transparent }; + private SamImageButton buttonPagingLast = new SamImageButton() { WidthRequest = 32, HeightRequest = 32, Aspect = Aspect.AspectFit, Padding = new Thickness(2, 4), BackgroundColor = Colors.Transparent }; + + //------------------------------------------------------------------- + // Construction. + public SamPanel_ItemListHeader(Config config) + { + this.config = config; + initialLabelFontSize = labelCaption.FontSize; + InitialiseComponents(); + } + + //------------------------------------------------------------------- + // Properties. + // Filter. + public SamPanel_ItemFilter? PanelFilter { get; private set; } + // Paging. + public uint PageNo { get { return paging.PageNo; } } + public ushort PageLength { get { return paging.PageLength; } } + public int TotalItems { get { return paging.TotalItems; } } + + //------------------------------------------------------------------- + // I n i t i a l i s e + //------------------------------------------------------------------- + private void InitialiseComponents() + { + // Frame - to allow rounded corners. + Content = frame; + frame.Content = mainLayout; + + // Header. + mainLayout.Spacing = 0; + mainLayout.HorizontalOptions = LayoutOptions.StartAndExpand; + mainLayout.BackgroundColor = Colors.Transparent; + //headerLayout.BackgroundColor = Color.LightYellow; + mainLayout.Children.Add(headerLayout); + + // Header - Caption. + captionLabelView.VerticalOptions = LayoutOptions.Center; + labelCaption.FontAttributes = FontAttributes.Bold; + labelCaption.HorizontalOptions = LayoutOptions.StartAndExpand; + labelCaption.VerticalOptions = LayoutOptions.CenterAndExpand; + labelCaption.LineBreakMode = LineBreakMode.NoWrap; + labelCaption.PropertyChanging += LabelCaption_PropertyChanging; + // Label is embedded in view to ensure correct sizing. + captionLabelView.Content = labelCaption; + headerLayout.Children.Add(captionLabelView); + + // Header - Paging. + pagingStack.HorizontalOptions = LayoutOptions.EndAndExpand; + pagingStack.VerticalOptions = LayoutOptions.CenterAndExpand; + headerLayout.Children.Add(pagingStack); + labelPaging.VerticalOptions = LayoutOptions.CenterAndExpand; + pagingStack.Children.Add(labelPaging); + pagingStack.Children.Add(buttonPagingFirst); + pagingStack.Children.Add(buttonPagingPrev); + pagingStack.Children.Add(buttonPagingNext); + pagingStack.Children.Add(buttonPagingLast); + + // Paging actions. + buttonPagingFirst.Clicked += ButtonPagingFirst_Clicked; + buttonPagingPrev.Clicked += ButtonPagingPrev_Clicked; + buttonPagingNext.Clicked += ButtonPagingNext_Clicked; + buttonPagingLast.Clicked += ButtonPagingLast_Clicked; + + // Complete panel configuration. + ConfigurePanel(); + } + + private void LabelCaption_PropertyChanging(object? sender, PropertyChangingEventArgs e) + { + if (e.PropertyName.EqualsCI("Height")) + { + } + } + + //------------------------------------------------------------------- + // C o n f i g u r e P a n e l + //------------------------------------------------------------------- + private void ConfigurePanel() + { + if (config.Margin != null) + frame.Margin = (Thickness)config.Margin; + + // Header. + labelCaption.Text = StringUtil.EmptyOnNull(config.Caption); + frame.Padding = new Thickness(config.HeaderBorderWidth); + frame.CornerRadius = config.HeaderBorderRadius; + frame.BorderColor = config.HeaderBorderColor; + frame.BackgroundColor = config.HeaderBackgroundColor; + + // Labels. + labelCaption.FontSize = initialLabelFontSize * config.CaptionLabelFontSizeRatio; + labelPaging.FontSize = initialLabelFontSize * config.PagingLabelFontSizeRatio; + if (config.LabelMargin != null) + { + labelCaption.Margin = (Thickness)config.LabelMargin; + labelPaging.Margin = (Thickness)config.LabelMargin; + } + + // Paging controls. + buttonPagingFirst.Source = SamImageUtil.GetImageFromByteArray(SacsResourceHelper.GetResourceImage(SacsResourceHelper.ImageResource.Arrow_Left_Double_Black_24_png)); + buttonPagingFirst.WidthRequest = Math.Max(Config.PagingButtonWidthMin, Math.Min(Config.PagingButtonWidthMax, config.PagingButtonWidth)); + buttonPagingFirst.HeightRequest = Math.Max(Config.PagingButtonHeightMin, Math.Min(Config.PagingButtonHeightMax, config.PagingButtonHeight)); + buttonPagingPrev.Source = SamImageUtil.GetImageFromByteArray(SacsResourceHelper.GetResourceImage(SacsResourceHelper.ImageResource.Arrow_Left_Black_24_png)); + buttonPagingPrev.WidthRequest = Math.Max(Config.PagingButtonWidthMin, Math.Min(Config.PagingButtonWidthMax, config.PagingButtonWidth)); + buttonPagingPrev.HeightRequest = Math.Max(Config.PagingButtonHeightMin, Math.Min(Config.PagingButtonHeightMax, config.PagingButtonHeight)); + buttonPagingNext.Source = SamImageUtil.GetImageFromByteArray(SacsResourceHelper.GetResourceImage(SacsResourceHelper.ImageResource.Arrow_Right_Black_24_png)); + buttonPagingNext.WidthRequest = Math.Max(Config.PagingButtonWidthMin, Math.Min(Config.PagingButtonWidthMax, config.PagingButtonWidth)); + buttonPagingNext.HeightRequest = Math.Max(Config.PagingButtonHeightMin, Math.Min(Config.PagingButtonHeightMax, config.PagingButtonHeight)); + buttonPagingLast.Source = SamImageUtil.GetImageFromByteArray(SacsResourceHelper.GetResourceImage(SacsResourceHelper.ImageResource.Arrow_Right_Double_Black_24_png)); + buttonPagingLast.WidthRequest = Math.Max(Config.PagingButtonWidthMin, Math.Min(Config.PagingButtonWidthMax, config.PagingButtonWidth)); + buttonPagingLast.HeightRequest = Math.Max(Config.PagingButtonHeightMin, Math.Min(Config.PagingButtonHeightMax, config.PagingButtonHeight)); + RefreshPaging(); + + // Property type filters. + SamPanel_ItemFilter.Config propertyFilterConfig = new SamPanel_ItemFilter.Config(); + propertyFilterConfig.FilterPropertyTypes.AddRange(config.FilterPropertyTypes); + propertyFilterConfig.FiltersToDisplay = config.FiltersToDisplay; + if (PanelFilter == null) + { + PanelFilter = new SamPanel_ItemFilter(propertyFilterConfig); + mainLayout.Children.Add(PanelFilter); + } + else + { + PanelFilter.SetConfig(propertyFilterConfig); + } + } + + //------------------------------------------------------------------- + // P a g i n g + //------------------------------------------------------------------- + public void SetPaging(uint pageNo, ushort pageLength, int totalItems) + { + paging.PageNo = pageNo; + paging.PageLength = pageLength; + paging.TotalItems = totalItems; + RefreshPaging(); + } + private void RefreshPaging() + { + String pagingText = ""; + Boolean paged = (paging.Paged && paging.TotalPages > 1); + if (paging.TotalItems > 0) + { + if (paged) + pagingText = "Page " + paging.PageNo + " of " + paging.TotalPages; + else + pagingText = paging.TotalItems + " items"; + } + labelPaging.Text = pagingText; + // Control visibility. + labelPaging.IsVisible = !StringUtil.IsEmpty(labelPaging.Text); + buttonPagingFirst.IsVisible = paged; + buttonPagingPrev.IsVisible = paged; + buttonPagingNext.IsVisible = paged; + buttonPagingLast.IsVisible = paged; + // Button activity. + buttonPagingFirst.IsEnabled = paging.PageNo > 1; + buttonPagingPrev.IsEnabled = paging.PageNo > 1; + buttonPagingNext.IsEnabled = paging.PageNo < paging.TotalPages; + buttonPagingLast.IsEnabled = paging.PageNo < paging.TotalPages; + } + + //------------------------------------------------------------------- + // Paging events. + public enum PagingActionType + { + Unknown, + First, + Next, + Prev, + Last + } + public class PagingActionEventArgs : EventArgs + { + public PagingActionType PagingActionType { get; set; } = PagingActionType.Unknown; + } + public event EventHandler? PagingAction; + private void FirePagingActionEvent(PagingActionType pagingActionType) + { + PagingActionEventArgs filterChangedEventArgs = new PagingActionEventArgs() + { + PagingActionType = pagingActionType, + }; + if (PagingAction != null) PagingAction.Invoke(this, filterChangedEventArgs); + } + + //------------------------------------------------------------------- + // Paging actions. + private void ButtonPagingFirst_Clicked(object? sender, EventArgs e) + { + FirePagingActionEvent(PagingActionType.First); + } + private void ButtonPagingPrev_Clicked(object? sender, EventArgs e) + { + FirePagingActionEvent(PagingActionType.Prev); + } + private void ButtonPagingNext_Clicked(object? sender, EventArgs e) + { + FirePagingActionEvent(PagingActionType.Next); + } + private void ButtonPagingLast_Clicked(object? sender, EventArgs e) + { + FirePagingActionEvent(PagingActionType.Last); + } + + //------------------------------------------------------------------- + // P a n e l E v e n t s + //------------------------------------------------------------------- + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Panels/SamPanel_ItemListSummary.cs b/SacsMobileMaui/Maui/Panels/SamPanel_ItemListSummary.cs new file mode 100644 index 0000000..ffb4111 --- /dev/null +++ b/SacsMobileMaui/Maui/Panels/SamPanel_ItemListSummary.cs @@ -0,0 +1,128 @@ +using Sarand.Net.Mobile.Maui.Controls; +using Sarand.Net.Mobile.Maui.Layouts; +using Sarand.Net.Mobile.Maui.Utils; +using Sarand.Net.Mobile.Maui.Views; +using Sarand.Net.Standard.Base.Core; +using Sarand.Net.Standard.Base.Helpers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Panels +{ + //======================================================================= + /// + /// Panel to display with item list where no filter required, eg. items associated with parent. + /// - Message shown to left + /// - Buttons shown to right + /// + public class SamPanel_ItemListSummary : SamContentView + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + private SacsMessage? message; + private bool showAddButton = false; + private double actionButtonSpacing = 4.0; + // Panel layout. + private SamStackLayout panelLayout = new SamStackLayout() { Orientation = StackOrientation.Horizontal }; + private SamContentView panelMessage = new SamContentView(); + private SamLabel labelMessage = new SamLabel() { HorizontalOptions = LayoutOptions.Start }; + // Action buttons. + private SamStackLayout panelActions = new SamStackLayout() { Orientation = StackOrientation.Horizontal }; + private SamImageButton buttonAddItem = new SamImageButton() { IsVisible = false, HorizontalOptions = LayoutOptions.End, VerticalOptions = LayoutOptions.Start }; + + //------------------------------------------------------------------- + // Construction. + public SamPanel_ItemListSummary() + { + // Panel layout. + panelLayout.HorizontalOptions = LayoutOptions.Fill; + Content = panelLayout; + + // Message. + panelMessage.HorizontalOptions = LayoutOptions.Fill; + panelMessage.VerticalOptions = LayoutOptions.Fill; + //panelMessage.BackgroundColor = Color.LightGoldenrodYellow; + panelLayout.Children.Add(panelMessage); + labelMessage.HorizontalOptions = LayoutOptions.Center; + labelMessage.VerticalOptions = LayoutOptions.Center; + panelMessage.Content = labelMessage; + + // Action buttons. + panelActions.HorizontalOptions = LayoutOptions.EndAndExpand; + panelLayout.Children.Add(panelActions); + + // 'Add' button. + buttonAddItem.IsVisible = showAddButton; + buttonAddItem.Padding = new Thickness(0, 0, actionButtonSpacing, 0); + buttonAddItem.BackgroundColor = Colors.Transparent; + buttonAddItem.Source = SamImageUtil.GetImageFromByteArray(SacsResourceHelper.GetResourceImage(SacsResourceHelper.ImageResource.IconShock_Add_Green_72_png)); + buttonAddItem.Clicked += ButtonAddItem_Clicked; + panelActions.Children.Add(buttonAddItem); + } + + //------------------------------------------------------------------- + // Properties. + // Message. + public double MessageFontSizeDefault { get { return labelMessage.FontSizeDefault; } } + public double MessageFontSize + { + get { return labelMessage.FontSize; } + set { labelMessage.FontSize = value; } + } + // Action buttons. + public double ActionButtonSpacing + { + get { return actionButtonSpacing; } + set + { + if (actionButtonSpacing == value) return; + buttonAddItem.Padding = new Thickness(0, 0, actionButtonSpacing, 0); + } + } + public bool ShowAddButton + { + get { return showAddButton; } + set { if (showAddButton == value) return; showAddButton = value; buttonAddItem.IsVisible = showAddButton; } + } + + //------------------------------------------------------------------- + // M e s s a g e + //------------------------------------------------------------------- + public void ClearMessage() + { + message = null; + labelMessage.Text = ""; + } + public void SetMessage(String message, SaMessageLevel messageLevel = SaMessageLevel.Info) + { + SetMessage(new SacsMessage(message, messageLevel)); + } + public void SetMessage(SacsMessage message) + { + this.message = message; + labelMessage.Text = (message != null ? message.Message : ""); + } + + //------------------------------------------------------------------- + // A c t i o n B u t t o n s + //------------------------------------------------------------------- + + //------------------------------------------------------------------- + // P a n e l E v e n t s + //------------------------------------------------------------------- + public event EventHandler? AddClicked; + protected virtual void ButtonAddItem_Clicked(object? sender, EventArgs e) + { + if (AddClicked != null) AddClicked.Invoke(sender, e); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Panels/SamPanel_Messages.cs b/SacsMobileMaui/Maui/Panels/SamPanel_Messages.cs new file mode 100644 index 0000000..99c1985 --- /dev/null +++ b/SacsMobileMaui/Maui/Panels/SamPanel_Messages.cs @@ -0,0 +1,77 @@ +using Sarand.Net.Mobile.Maui.Controls; +using Sarand.Net.Mobile.Maui.Layouts; +using Sarand.Net.Standard.Base.Core; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Panels +{ + //======================================================================= + public class SamPanel_Messages : SamPanel + { + //------------------------------------------------------------------- + // Definitions. + public class Config + { + } + + //------------------------------------------------------------------- + // Data members. + private Config config; + private readonly List messages = new List(); + // Components. + private SamStackLayout mainLayout = new SamStackLayout() { Orientation = StackOrientation.Vertical }; + + //------------------------------------------------------------------- + // Construction. + public SamPanel_Messages(Config config) + { + this.config = config; + Content = mainLayout; + } + + //------------------------------------------------------------------- + // Properties. + + //------------------------------------------------------------------- + // M e s s a g e s + //------------------------------------------------------------------- + public void ClearMessages() + { + messages.Clear(); + RefreshLayout(); + } + public void AddMessage(SacsMessage message) + { + messages.Add(message); + RefreshLayout(); + } + + //------------------------------------------------------------------- + // R e f r e s h L a y o u t + //------------------------------------------------------------------- + private void RefreshLayout() + { + // Reset layout. + IsVisible = messages.Count > 0; + mainLayout.Children.Clear(); + + foreach (SacsMessage message in messages) + { + SamPanel messagePanel = new SamPanel(); + messagePanel.Content = new SamLabel() { Text = message.Message }; + mainLayout.Children.Add(messagePanel); + } + } + + //------------------------------------------------------------------- + // P a n e l E v e n t s + //------------------------------------------------------------------- + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Panels/SamPanel_Page_Footer.cs b/SacsMobileMaui/Maui/Panels/SamPanel_Page_Footer.cs new file mode 100644 index 0000000..fced510 --- /dev/null +++ b/SacsMobileMaui/Maui/Panels/SamPanel_Page_Footer.cs @@ -0,0 +1,135 @@ +using Sarand.Net.Mobile.Maui.App; +using Sarand.Net.Mobile.Maui.Controls; +using Sarand.Net.Mobile.Maui.Layouts; +using Sarand.Net.Mobile.Maui.Utils; +using Sarand.Net.Mobile.Maui.Views; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Panels +{ + //======================================================================= + public class SamPanel_Page_Footer : SamPanel + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + // Layout. + private VerticalStackLayout panelFooter = new VerticalStackLayout() { BackgroundColor = Sam.Visuals.Page.Footer.BackgroundColor }; + private SamBoxView panelBorderTop = new SamBoxView() { BackgroundColor = Sam.Visuals.Page.Footer.BorderColor, HeightRequest = Sam.Visuals.Page.Footer.BorderStrokeWidthTop }; + private SamBoxView panelBorderBottom = new SamBoxView() { BackgroundColor = Sam.Visuals.Page.Footer.BorderColor, HeightRequest = Sam.Visuals.Page.Footer.BorderStrokeWidthBottom }; + // Grid. + private SamGrid gridFooter = new SamGrid() { Padding = Sam.Visuals.Page.Footer.Padding }; + private ColumnDefinition colLeft = new ColumnDefinition(GridLength.Star); + private ColumnDefinition colMiddle = new ColumnDefinition(GridLength.Auto); + private ColumnDefinition colRight = new ColumnDefinition(GridLength.Star); + // Panels. + private VerticalStackLayout panelLeft = new VerticalStackLayout() { HorizontalOptions = LayoutOptions.Start }; + private VerticalStackLayout panelMiddle = new VerticalStackLayout() { HorizontalOptions = LayoutOptions.Center }; + private VerticalStackLayout panelRight = new VerticalStackLayout() { HorizontalOptions = LayoutOptions.End }; + // Date-time display. + private String dateTimeFormat = "ddd d-MMM-yyyy HH:mm:ss"; + private IDispatcherTimer? timerDateTime; + private Sam.DisplayPosition dateTimeDisplay = Sam.Visuals.Page.Footer.DateTimeDisplay; + private SamLabel labelDateTime = new SamLabel() { FontSize = 12.0, HorizontalTextAlignment = TextAlignment.Center }; + + //------------------------------------------------------------------- + // Construction. + public SamPanel_Page_Footer() + { + // Footer panel. + Content = panelFooter; + + // Footer border top. + panelFooter.Children.Add(panelBorderTop); + + // Footer grid. + gridFooter.ColumnDefinitions.Add(colLeft); + gridFooter.ColumnDefinitions.Add(colMiddle); + gridFooter.ColumnDefinitions.Add(colRight); + gridFooter.Add(panelLeft, 0, 0); + gridFooter.Add(panelMiddle, 1, 0); + gridFooter.Add(panelRight, 2, 0); + panelFooter.Children.Add(gridFooter); + + // Footer border bottom. + panelFooter.Children.Add(panelBorderBottom); + + RefreshComponents(); + } + + //------------------------------------------------------------------- + // Properties. + public Sam.DisplayPosition DateTimeDisplay + { + get { return dateTimeDisplay; } + set { dateTimeDisplay = value; RefreshComponents(); } + } + public String DateTimeFormat + { + get { return dateTimeFormat; } + set { dateTimeFormat = value; RefreshComponents(); } + } + + //------------------------------------------------------------------- + // Events. + protected override void OnParentChanged() + { + base.OnParentChanged(); + if (Parent == null) + ClearDateTimeTimer(); + } + + //------------------------------------------------------------------- + // DateTime display. + private void ClearDateTimeTimer() + { + if (timerDateTime != null && timerDateTime.IsRunning) + timerDateTime.Stop(); + } + + private void TimerDateTime_Tick(object? sender, EventArgs e) + { + String dateTimeValue = DateTime.Now.ToString(dateTimeFormat); + if (!labelDateTime.Text.Equals(dateTimeValue)) + labelDateTime.Text = dateTimeValue; + } + + //------------------------------------------------------------------- + private void RefreshComponents() + { + bool contentDisplayed = false; + + // Date time. + ClearDateTimeTimer(); + panelLeft.Children.Remove(labelDateTime); + panelMiddle.Children.Remove(labelDateTime); + panelRight.Children.Remove(labelDateTime); + if (dateTimeDisplay == Sam.DisplayPosition.Left) + panelLeft.Children.Add(labelDateTime); + else if (dateTimeDisplay == Sam.DisplayPosition.Middle) + panelMiddle.Children.Add(labelDateTime); + else if (dateTimeDisplay == Sam.DisplayPosition.Right) + panelRight.Children.Add(labelDateTime); + if (dateTimeDisplay != Sam.DisplayPosition.None) + { + contentDisplayed = true; + timerDateTime = SamTimerUtil.DoTimer(this, TimeSpan.FromMilliseconds(250), true, TimerDateTime_Tick); + timerDateTime.Start(); + } + + // Hide panel if nothing displayed. + if (contentDisplayed) + IsVisible = true; + else IsVisible = false; + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Panels/SamPanel_Page_Header.cs b/SacsMobileMaui/Maui/Panels/SamPanel_Page_Header.cs new file mode 100644 index 0000000..9cc4c8b --- /dev/null +++ b/SacsMobileMaui/Maui/Panels/SamPanel_Page_Header.cs @@ -0,0 +1,205 @@ +using Microsoft.Maui.Controls.Internals; +using Sarand.Net.Mobile.Maui.App; +using Sarand.Net.Mobile.Maui.Controls; +using Sarand.Net.Mobile.Maui.Layouts; +using Sarand.Net.Mobile.Maui.Utils; +using Sarand.Net.Mobile.Maui.Views; +using Sarand.Net.Standard.Base.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Panels +{ + //======================================================================= + public class SamPanel_Page_Header : SamPanel + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + // Layout. + private SamBoxView panelBorderTop = new SamBoxView() { BackgroundColor = Sam.Visuals.Page.Header.BorderColor, HeightRequest = Sam.Visuals.Page.Header.BorderStrokeWidthTop }; + private VerticalStackLayout panelHeader = new VerticalStackLayout() { BackgroundColor = Sam.Visuals.Page.Header.BackgroundColor }; + private SamBoxView panelBorderBottom = new SamBoxView() { BackgroundColor = Sam.Visuals.Page.Header.BorderColor, HeightRequest = Sam.Visuals.Page.Header.BorderStrokeWidthBottom }; + // Grid. + private SamGrid gridHeader = new SamGrid() { Padding = Sam.Visuals.Page.Header.Padding }; + private ColumnDefinition colLeft = new ColumnDefinition(GridLength.Star); + private ColumnDefinition colMiddle = new ColumnDefinition(GridLength.Auto); + private ColumnDefinition colRight = new ColumnDefinition(GridLength.Star); + // Panels. + private VerticalStackLayout panelLeft = new VerticalStackLayout() { HorizontalOptions = LayoutOptions.Start }; + private VerticalStackLayout panelMiddle = new VerticalStackLayout() { HorizontalOptions = LayoutOptions.Center }; + private VerticalStackLayout panelRight = new VerticalStackLayout() { HorizontalOptions = LayoutOptions.End }; + // Caption. + private SamLabel labelCaption = new SamLabel() { HorizontalOptions = LayoutOptions.Center }; + private Sam.DisplayPosition captionDisplay = Sam.DisplayPosition.Middle; + // Text labels. + private SamLabel labelLeft = new SamLabel() { HorizontalOptions = LayoutOptions.Start }; + private SamLabel labelRight= new SamLabel() { HorizontalOptions = LayoutOptions.End }; + // Toolbar. + private Sam.DisplayPosition toolbarDisplay = Sam.Visuals.Page.Header.ToolbarDisplay; + private HorizontalStackLayout panelToolbar = new HorizontalStackLayout() { }; + private bool display_ToolbarItem_Back = Sam.Visuals.Page.Header.Display_ToolbarItem_Back; + private Button toolbarItem_Back = new Button() { WidthRequest = 16, HeightRequest = 16, Text="<", Padding=new Thickness(0), BorderWidth = 0.0, BorderColor = Colors.DarkOliveGreen }; + + //------------------------------------------------------------------- + // Construction. + public SamPanel_Page_Header() + { + InitialiseComponents(); + } + + //------------------------------------------------------------------- + // Properties. + public String Caption + { + get { return labelCaption.Text; } + set { labelCaption.Text = value; ConfigureComponents(); } + } + public Sam.DisplayPosition CaptionDisplay + { + get { return captionDisplay; } + set { captionDisplay = value; ConfigureComponents(); } + } + + // Text labels. + public String TextLeft + { + get { return labelLeft.Text; } + set { labelLeft.Text = value; ConfigureComponents(); } + } + public String TextRight + { + get { return labelRight.Text; } + set { labelRight.Text = value; ConfigureComponents(); } + } + + // Toolbar. + public Sam.DisplayPosition ToolbarDisplay + { + get { return toolbarDisplay; } + set { toolbarDisplay = value; ConfigureComponents(); } + } + public bool Display_ToolbarItem_Back + { + get { return display_ToolbarItem_Back; } + set { display_ToolbarItem_Back = value; ConfigureComponents(); } + } + + //------------------------------------------------------------------- + // Components. + + private void InitialiseComponents() + { + // Header panel. + Content = panelHeader; + + // Top border. + panelBorderTop.Margin = new Thickness(0, 0, 0, Sam.Visuals.Page.Header.Padding.Top); + panelHeader.Children.Add(panelBorderTop); + + // Header grid. + gridHeader.Margin = new Thickness(Sam.Visuals.Page.Header.Padding.Left, 0, Sam.Visuals.Page.Header.Padding.Right, 0); + gridHeader.ColumnDefinitions.Add(colLeft); + gridHeader.ColumnDefinitions.Add(colMiddle); + gridHeader.ColumnDefinitions.Add(colRight); + gridHeader.Add(panelLeft, 0, 0); + gridHeader.Add(panelMiddle, 1, 0); + gridHeader.Add(panelRight, 2, 0); + panelHeader.Children.Add(gridHeader); + + // Bottom border. + panelBorderBottom.Margin = new Thickness(0, Sam.Visuals.Page.Header.Padding.Bottom, 0, 0); + panelHeader.Children.Add(panelBorderBottom); + + // Configure standard toolbar icons. + toolbarItem_Back.Clicked += ToolbarItem_Back_Clicked; + } + + public override void ConfigureComponents() + { + base.ConfigureComponents(); + bool contentDisplayed = false; + + // Caption. + panelLeft.Children.Remove(labelCaption); + panelMiddle.Children.Remove(labelCaption); + panelRight.Children.Remove(labelCaption); + if (captionDisplay != Sam.DisplayPosition.None && !StringUtil.IsBlank(labelCaption.Text)) + { + contentDisplayed = true; + if (captionDisplay == Sam.DisplayPosition.Left) + panelLeft.Children.Add(labelCaption); + else if (captionDisplay == Sam.DisplayPosition.Middle) + panelMiddle.Children.Add(labelCaption); + else if (captionDisplay == Sam.DisplayPosition.Right) + panelRight.Children.Add(labelCaption); + } + + // Text labels. + panelLeft.Children.Remove(labelLeft); + if (!StringUtil.IsBlank(labelLeft.Text)) + { + contentDisplayed = true; + panelLeft.Children.Add(labelLeft); + } + panelRight.Children.Remove(labelRight); + if (!StringUtil.IsBlank(labelRight.Text)) + { + contentDisplayed = true; + panelRight.Children.Add(labelRight); + } + + // Toolbar. + panelLeft.Children.Remove(panelToolbar); + panelMiddle.Children.Remove(panelToolbar); + panelRight.Children.Remove(panelToolbar); + panelToolbar.Children.Clear(); + + // Toolbar icons. + if (display_ToolbarItem_Back) + panelToolbar.Children.Add(toolbarItem_Back); + if (panelToolbar.Children.Any() && ToolbarDisplay != Sam.DisplayPosition.None) + { + contentDisplayed = true; + if (ToolbarDisplay == Sam.DisplayPosition.Left) + panelLeft.Children.Add(panelToolbar); + else if (ToolbarDisplay == Sam.DisplayPosition.Middle) + panelMiddle.Children.Add(panelToolbar); + else if (ToolbarDisplay == Sam.DisplayPosition.Right) + panelRight.Children.Add(panelToolbar); + } + + // Hide panel if nothing displayed. + if (contentDisplayed) + IsVisible = true; + else IsVisible = false; + } + + //------------------------------------------------------------------- + // Toolbar actions. + + private void ToolbarItem_Back_Clicked(object? sender, EventArgs e) + { + //if (Navigation.NavigationStack.Where(item => System.Object.ReferenceEquals(item, this)).Any()) + Page? page = this.GetPage(); + if (Navigation.NavigationStack.Any() && System.Object.ReferenceEquals(Navigation.NavigationStack.Last(), page)) + { + Navigation.PopAsync(); + return; + } + if (Navigation.ModalStack.Where(item => System.Object.ReferenceEquals(item, page)).Any()) + { + Navigation.PopModalAsync(); + return; + } + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Panels/SamPanel_Progress.cs b/SacsMobileMaui/Maui/Panels/SamPanel_Progress.cs new file mode 100644 index 0000000..bf36767 --- /dev/null +++ b/SacsMobileMaui/Maui/Panels/SamPanel_Progress.cs @@ -0,0 +1,94 @@ +using Sarand.Net.Mobile.Maui.Controls; +using Sarand.Net.Mobile.Maui.Layouts; +using Sarand.Net.Mobile.Maui.Views; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Panels +{ + //======================================================================= + public class SamPanel_Progress : SamContentView + { + //------------------------------------------------------------------- + // Definitions. + public class Config + { + } + + //------------------------------------------------------------------- + // Data members. + private Config config; + // Panel layout. + private SamGrid gridPanel = new SamGrid(); + private SamContentView viewPanel = new SamContentView(); + private SamLabel labelProgressMessage = new SamLabel(); + + //------------------------------------------------------------------- + // Construction. + public SamPanel_Progress(Config config) + { + this.config = config; + InitialiseComponents(); + } + + //------------------------------------------------------------------- + // Properties. + public double ProgressMessageFontSizeDefault { get { return labelProgressMessage.FontSizeDefault; } } + public double ProgressMessageFontSize { get { return labelProgressMessage.FontSize; } set { labelProgressMessage.FontSize = value; } } + public FontAttributes ProgressMessageFontAttributes { get { return labelProgressMessage.FontAttributes; } set { labelProgressMessage.FontAttributes = value; } } + public Color ProgressMessageColor { get { return labelProgressMessage.TextColor; } set { labelProgressMessage.TextColor = value; } } + public String ProgressMessage { get { return labelProgressMessage.Text; } set { labelProgressMessage.Text = value; } } + public Thickness ProgressMessagePadding { get { return viewPanel.Padding; } set { viewPanel.Padding = value; } } + public Color ProgressMessageBackgroundColor { get { return viewPanel.BackgroundColor; } set { viewPanel.BackgroundColor = value; } } + + //------------------------------------------------------------------- + // I n i t i a l i s e + //------------------------------------------------------------------- + private void InitialiseComponents() + { + // Layout is a 3x3 grid with only the central cell populated. + // All other cells are transparent/opaque. + gridPanel.BackgroundColor = new Color(0, 0, 0, 0.5f); + gridPanel.HorizontalOptions = LayoutOptions.FillAndExpand; + gridPanel.VerticalOptions = LayoutOptions.FillAndExpand; + gridPanel.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Star }); + gridPanel.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto }); + gridPanel.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Star }); + gridPanel.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Star }); + gridPanel.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto }); + gridPanel.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Star }); + Content = gridPanel; + + // The panel's view. + viewPanel.Padding = new Thickness(12.0); + viewPanel.BackgroundColor = Colors.WhiteSmoke; + viewPanel.HorizontalOptions = LayoutOptions.Center; + viewPanel.VerticalOptions = LayoutOptions.Center; + gridPanel.Add(viewPanel, 1, 1); + + // Progress message. + viewPanel.Content = labelProgressMessage; + + // Complete panel configuration. + ConfigurePanel(); + } + + //------------------------------------------------------------------- + // C o n f i g u r e P a n e l + //------------------------------------------------------------------- + private void ConfigurePanel() + { + // Panel initialisation that depends on the configuration. + } + + //------------------------------------------------------------------- + // P a n e l E v e n t s + //------------------------------------------------------------------- + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Panels/SamPanel_PropertySummary.cs b/SacsMobileMaui/Maui/Panels/SamPanel_PropertySummary.cs new file mode 100644 index 0000000..631e691 --- /dev/null +++ b/SacsMobileMaui/Maui/Panels/SamPanel_PropertySummary.cs @@ -0,0 +1,141 @@ +using Sarand.Net.Mobile.Maui.Controls; +using Sarand.Net.Mobile.Maui.Layouts; +using Sarand.Net.Mobile.Maui.Views; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Panels +{ + //======================================================================= + public class SamPanel_PropertySummary : SamContentView + { + //------------------------------------------------------------------- + // Definitions. + private class PropertyData + { + public String Caption { get; set; } = ""; + public String Value { get; set; } = ""; + } + + //------------------------------------------------------------------- + // Data members. + private float internalFrameRadiusFactor = 0.8f; + private readonly List properties = new List(); + // Panel components. + private SamFrame framePanel = new SamFrame(); + private SamFrame frameInternal = new SamFrame(); + private SamGrid gridProperties = new SamGrid(); + + //------------------------------------------------------------------- + // Construction. + public SamPanel_PropertySummary() + { + // View properties. + //BackgroundColor = Color.Transparent; + framePanel.CornerRadius = 8.0f; + framePanel.Padding = new Thickness(2.0); + framePanel.BackgroundColor = Colors.Transparent; + framePanel.BorderColor = framePanel.BorderColor; + Content = framePanel; + + // Frame. + frameInternal.CornerRadius = framePanel.CornerRadius * internalFrameRadiusFactor; + frameInternal.Padding = new Thickness(0); + frameInternal.BorderColor = Colors.White; + frameInternal.BackgroundColor = Colors.White; + framePanel.Content = frameInternal; + frameInternal.Content = gridProperties; + + // Properties grid. + gridProperties.Padding = new Thickness(4.0); + gridProperties.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto }); + gridProperties.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Star }); + + // Property styling. + DefaultFontSize = new SamLabel().FontSize; + FontSize = DefaultFontSize; + + ConfigureComponents(); + } + + //------------------------------------------------------------------- + // Properties. + public Color BorderColor + { + get { return framePanel.BorderColor; } + set + { + framePanel.BorderColor = value; + framePanel.BackgroundColor = value; + } + } + public Thickness BorderWidth { get { return framePanel.Padding; } set { framePanel.Padding = value; } } + public float CornerRadius + { + get { return framePanel.CornerRadius; } + set + { + framePanel.CornerRadius = value; + frameInternal.CornerRadius = framePanel.CornerRadius * internalFrameRadiusFactor; + } + } + public Color PanelBackgroundColor + { + get { return frameInternal.BackgroundColor; } + set + { + frameInternal.BorderColor = value; + frameInternal.BackgroundColor = value; + } + } + // Property label styling. + public double DefaultFontSize { get; } + public double FontSize { get; set; } + + //------------------------------------------------------------------- + // S u m m a r y P r o p e r t i e s + //------------------------------------------------------------------- + public void AddProperty(String caption, String value) + { + properties.Add(new PropertyData() { Caption = caption, Value = value }); + RefreshProperties(); + } + public void ClearProperties() + { + properties.Clear(); + RefreshProperties(); + } + private void RefreshProperties() + { + // Clear existing properties. + gridProperties.Children.Clear(); + gridProperties.RowDefinitions.Clear(); + + foreach (PropertyData property in properties) + { + int rowIdx = gridProperties.RowDefinitions.Count; + gridProperties.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto }); + gridProperties.Add(new SamLabel() { Text = property.Caption, FontSize = FontSize, HorizontalOptions = LayoutOptions.End }, 0, rowIdx); + gridProperties.Add(new SamLabel() { Text = property.Value, FontSize = FontSize, HorizontalOptions = LayoutOptions.StartAndExpand, VerticalOptions = LayoutOptions.StartAndExpand }, 1, rowIdx); + } + } + + //------------------------------------------------------------------- + // C o n f i g u r e C o m p o n e n t s + //------------------------------------------------------------------- + public override void ConfigureComponents() + { + base.ConfigureComponents(); + } + + //------------------------------------------------------------------- + // P a n e l E v e n t s + //------------------------------------------------------------------- + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Panels/SamPanel_Tab.cs b/SacsMobileMaui/Maui/Panels/SamPanel_Tab.cs new file mode 100644 index 0000000..f1a906d --- /dev/null +++ b/SacsMobileMaui/Maui/Panels/SamPanel_Tab.cs @@ -0,0 +1,82 @@ + +using Sarand.Net.Mobile.Maui.Views; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Panels +{ + //======================================================================= + public class SamPanel_Tab : SamPanel + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + + //------------------------------------------------------------------- + // Construction. + public SamPanel_Tab() + { + } + + //------------------------------------------------------------------- + // Properties. + + //------------------------------------------------------------------- + // C o n f i g u r e C o m p o n e n t s + //------------------------------------------------------------------- + public override void ConfigureComponents() + { + base.ConfigureComponents(); + } + + //------------------------------------------------------------------- + // C o n t r o l A c t i v i t y + //------------------------------------------------------------------- + public override void SetControlActivity() + { + } + public override void SetControlsReadOnly() + { + } + + //------------------------------------------------------------------- + // P a n e l E v e n t s + //------------------------------------------------------------------- + protected override void OnParentSet() + { + base.OnParentSet(); + } + //------------------------------------------------------------------- + protected override void OnPropertyChanging([CallerMemberName] string propertyName = "") + { + base.OnPropertyChanging(propertyName); + } + protected override void OnPropertyChanged([CallerMemberName] string propertyName = "") + { + base.OnPropertyChanged(propertyName); + } + //------------------------------------------------------------------- + protected override void OnChildAdded(Element child) + { + base.OnChildAdded(child); + } + protected override void OnChildRemoved(Element child, int oldLogicalIndex) + { + base.OnChildRemoved(child, oldLogicalIndex); + } + //------------------------------------------------------------------- + protected override void OnSizeAllocated(double width, double height) + { + base.OnSizeAllocated(width, height); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Panels/SamPanel_Tabbed.cs b/SacsMobileMaui/Maui/Panels/SamPanel_Tabbed.cs new file mode 100644 index 0000000..912f923 --- /dev/null +++ b/SacsMobileMaui/Maui/Panels/SamPanel_Tabbed.cs @@ -0,0 +1,212 @@ +using Sarand.Net.Mobile.Maui.Views; +using Sarand.Net.Standard.Base.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Panels +{ + //======================================================================= + public class SamPanel_Tabbed : SamPanel + { + //------------------------------------------------------------------- + // Definitions. + private class TabPanelData + { + public TabPanelData(int tabPos, SamPanel_TabCaption tabCaptionPanel, SamPanel_Tab tabPanel) + { + TabPos = tabPos; + TabCaptionPanel = tabCaptionPanel; + TabPanel = tabPanel; + } + public int TabPos { get; } + public SamPanel_TabCaption TabCaptionPanel { get; } + public SamPanel_Tab TabPanel { get; } + } + + /// + /// Tab Caption panel + /// + public class SamPanel_TabCaption : SamPanel + { + // Properties. + private SamPanel_Tabbed TabbedPanel { get; } + public int TabPos { get; } + public String Caption { get; } + // Data members. + private static readonly Color ActiveBackgroundColor = Colors.WhiteSmoke; + private static readonly Color ActiveBorderColor = Colors.DarkSlateBlue; + private static readonly Color InactiveBackgroundColor = Colors.LightGray; + private static readonly Color InactiveBorderColor = Colors.SlateBlue; + private Border border = new Border() { Stroke = InactiveBorderColor, StrokeThickness = 2.0 }; + private TapGestureRecognizer tabCaptionTapGesture = new TapGestureRecognizer(); + public SamPanel_TabCaption(SamPanel_Tabbed tabbedPanel, int tabPos, String caption) + { + TabbedPanel = tabbedPanel; + TabPos = tabPos; + Caption = caption; + Content = border; + tabCaptionTapGesture.Tapped += TabCaptionTapGesture_Tapped; + GestureRecognizers.Add(tabCaptionTapGesture); + Deactivate(); + } + private void TabCaptionTapGesture_Tapped(object? sender, TappedEventArgs e) + { + TabbedPanel.TabCaptionTapped(sender, e, TabPos); + } + public void Activate() + { + BackgroundColor = ActiveBackgroundColor; + border.Stroke = ActiveBorderColor; + } + public void Deactivate() + { + BackgroundColor = InactiveBackgroundColor; + border.Stroke = InactiveBorderColor; + } + } + + //------------------------------------------------------------------- + // Data members. + + // Content. + private VerticalStackLayout contentStack = new VerticalStackLayout() { }; + private HorizontalStackLayout panelTabCaptions = new HorizontalStackLayout() { Spacing = 8.0 }; + private ScrollView scrollTabPanels = new ScrollView() { }; + private VerticalStackLayout panelTabPanels = new VerticalStackLayout() { }; + + // Tab panels. + private int tabCount = 0; + private readonly List tabPanels = new List(); + + //------------------------------------------------------------------- + // Construction. + public SamPanel_Tabbed() + { + // Content. + Content = contentStack; + + // Tab captions. + contentStack.Children.Add(panelTabCaptions); + + // Tab panels. + contentStack.Children.Add(scrollTabPanels); + scrollTabPanels.Content = panelTabPanels; + } + + //------------------------------------------------------------------- + // Properties. + + //------------------------------------------------------------------- + // Manage tabs. + + public void AddTabPanel(String caption, SamPanel_Tab tabPanel) + { + tabCount++; + + // Tab caption. + if (StringUtil.IsBlank(caption)) + caption = $"Tab #{tabCount}"; + SamPanel_TabCaption panelTabCaption = new SamPanel_TabCaption(this, tabCount, caption); + panelTabCaptions.Children.Add(panelTabCaption); + + // Tab panel. + panelTabPanels.Children.Add(tabPanel); + + // Tab panel data. + TabPanelData tabPanelData = new TabPanelData(tabCount, panelTabCaption, tabPanel); + tabPanels.Add(tabPanelData); + + if (tabCount == 1) + { + panelTabCaption.Activate(); + } + } + + public void ClearTabPanels() + { + tabCount = 0; + tabPanels.Clear(); + panelTabCaptions.Children.Clear(); + panelTabPanels.Children.Clear(); + } + + //------------------------------------------------------------------- + // Actions. + + private void TabCaptionTapped(object? sender, TappedEventArgs e, int tabPos) + { + foreach (TabPanelData tabPanel in tabPanels) + { + if (tabPanel.TabPos == tabPos) + { + tabPanel.TabCaptionPanel.Activate(); + tabPanel.TabPanel.IsVisible = true; + } + else + { + tabPanel.TabCaptionPanel.Deactivate(); + tabPanel.TabPanel.IsVisible = false; + } + } + } + + //------------------------------------------------------------------- + // C o n f i g u r e C o m p o n e n t s + //------------------------------------------------------------------- + public override void ConfigureComponents() + { + base.ConfigureComponents(); + } + + //------------------------------------------------------------------- + // C o n t r o l A c t i v i t y + //------------------------------------------------------------------- + public override void SetControlActivity() + { + } + public override void SetControlsReadOnly() + { + } + + //------------------------------------------------------------------- + // P a n e l E v e n t s + //------------------------------------------------------------------- + protected override void OnParentSet() + { + base.OnParentSet(); + } + + //------------------------------------------------------------------- + protected override void OnPropertyChanging([CallerMemberName] string propertyName = "") + { + base.OnPropertyChanging(propertyName); + } + protected override void OnPropertyChanged([CallerMemberName] string propertyName = "") + { + base.OnPropertyChanged(propertyName); + } + + //------------------------------------------------------------------- + protected override void OnChildAdded(Element child) + { + base.OnChildAdded(child); + } + protected override void OnChildRemoved(Element child, int oldLogicalIndex) + { + base.OnChildRemoved(child, oldLogicalIndex); + } + + //------------------------------------------------------------------- + protected override void OnSizeAllocated(double width, double height) + { + base.OnSizeAllocated(width, height); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Panels/SamTabPanel.cs b/SacsMobileMaui/Maui/Panels/SamTabPanel.cs new file mode 100644 index 0000000..0235740 --- /dev/null +++ b/SacsMobileMaui/Maui/Panels/SamTabPanel.cs @@ -0,0 +1,52 @@ +using Sarand.Net.Mobile.Maui.Views; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Panels +{ + //======================================================================= + public class SamTabPanel : SamPanel + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + + //------------------------------------------------------------------- + // Construction. + public SamTabPanel(String caption, SamContentView panel) + { + Caption = caption; + + // This panel includes border layout around the actual tab panel content. + Padding = new Thickness(2.0); + BackgroundColor = Colors.LightSlateGray; + Content = panel; + } + + //------------------------------------------------------------------- + // Properties. + public String Caption { get; } + public Thickness BorderWidth + { + get { return Padding; } + set { if (Padding == value) return; Padding = value; } + } + public Color BorderColor + { + get { return BackgroundColor; } + set { if (BackgroundColor == value) return; BackgroundColor = value; } + } + + //------------------------------------------------------------------- + // T a b P a n e l s + //------------------------------------------------------------------- + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Utils/SamElementUtil.cs b/SacsMobileMaui/Maui/Utils/SamElementUtil.cs new file mode 100644 index 0000000..c5b69aa --- /dev/null +++ b/SacsMobileMaui/Maui/Utils/SamElementUtil.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Utils +{ + //======================================================================= + public static class SamElementUtil + { + //------------------------------------------------------------------- + /// + /// Identify the page fo rthis element. + /// + public static Page? GetPage(this Element element) + { + while (element != null) + { + if (element is Page) return element as Page; + element = element.Parent; + } + return null; + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Utils/SamFormUtil.cs b/SacsMobileMaui/Maui/Utils/SamFormUtil.cs new file mode 100644 index 0000000..bc07216 --- /dev/null +++ b/SacsMobileMaui/Maui/Utils/SamFormUtil.cs @@ -0,0 +1,49 @@ +using Sarand.Net.Standard.Base.App; +using Sarand.Net.Standard.Base.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Utils +{ + //======================================================================= + public static class SamFormsUtil + { + //------------------------------------------------------------------- + // D i s p l a y A l e r t a n d W a i t + //------------------------------------------------------------------- + public static void DisplayAlertSync(String title, String message, String cancel = "OK") + { + if (Application.Current?.MainPage == null) + { + SaLogger.Warn(SysUtil.Fn + " Null main page. Message: " + message); + return; + } + SamThreadUtil.InvokeOnMainThreadSync(async () => await Application.Current.MainPage.DisplayAlert(title, message, cancel)); + } + public static bool DisplayConfirmSync(String title, String message, String accept = "Yes", String cancel = "No") + { + if (Application.Current?.MainPage == null) + { + SaLogger.Warn(SysUtil.Fn + " Null main page. Message: " + message); + return false; + } + var tcs = new TaskCompletionSource(); + MainThread.BeginInvokeOnMainThread(async () => + { + try + { + bool result = await Application.Current.MainPage.DisplayAlert(title, message, accept, cancel); + tcs.SetResult(result); + } + catch (Exception ex) { tcs.SetException(ex); } + }); + return tcs.Task.Result; + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Utils/SamImageUtil.cs b/SacsMobileMaui/Maui/Utils/SamImageUtil.cs new file mode 100644 index 0000000..cb78529 --- /dev/null +++ b/SacsMobileMaui/Maui/Utils/SamImageUtil.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Utils +{ + //======================================================================= + public static class SamImageUtil + { + //------------------------------------------------------------------- + /// + /// Method that uses the ImageConverter object in .Net Framework to convert a byte array, + /// presumably containing a JPEG or PNG file image, into an ImageSource. + /// + public static ImageSource GetImageFromByteArray(byte[] imageAsBytes) + { + return ImageSource.FromStream(() => new MemoryStream(imageAsBytes)); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Utils/SamPageUtil.cs b/SacsMobileMaui/Maui/Utils/SamPageUtil.cs new file mode 100644 index 0000000..b2fbd2d --- /dev/null +++ b/SacsMobileMaui/Maui/Utils/SamPageUtil.cs @@ -0,0 +1,18 @@ +using Microsoft.Maui.Graphics; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Utils +{ + //======================================================================= + public static class SamPageUtil + { + //------------------------------------------------------------------- + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Utils/SamResourceUtil.cs b/SacsMobileMaui/Maui/Utils/SamResourceUtil.cs new file mode 100644 index 0000000..3985cbe --- /dev/null +++ b/SacsMobileMaui/Maui/Utils/SamResourceUtil.cs @@ -0,0 +1,61 @@ +using Sarand.Net.Standard.Base.App; +using Sarand.Net.Standard.Base.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Utils +{ + //======================================================================= + public class SamResourceUtil + { + //------------------------------------------------------------------- + // Resource as Stream. + + public static Stream? GetResourceStream(String resourcePath) + { + return GetResourceStream(Assembly.GetExecutingAssembly(), resourcePath); + } + + //------------------------------------------------------------------- + public static Stream? GetResourceStream(Assembly assembly, String resourcePath) + { + Stream? stream = assembly.GetManifestResourceStream(resourcePath); + if (stream != null) return stream; + + foreach (var res in assembly.GetManifestResourceNames()) + { + //SaLogger.Info(SysUtil.Fn + $" Resource: {res.ToString()}"); + + // Read source file + stream = assembly.GetManifestResourceStream(res); + //using var reader = new StreamReader(stream); + //var content = reader.ReadToEnd(); + + // generate target path inside data folder + //string targetFile = System.IO.Path.Combine(FileSystem.Current.AppDataDirectory, res); + + // write file into data folder + //using FileStream outputStream = System.IO.File.OpenWrite(targetFile); + //using StreamWriter streamWriter = new StreamWriter(outputStream); + + //streamWriter.Write(content); + } + return null; + } + + //------------------------------------------------------------------- + // Log resources. + public static void LogResources(Assembly assembly) + { + foreach (var res in assembly.GetManifestResourceNames()) + SaLogger.Info(SysUtil.Fn + $" Resource: {res.ToString()}"); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Utils/SamThreadUtil.cs b/SacsMobileMaui/Maui/Utils/SamThreadUtil.cs new file mode 100644 index 0000000..2502347 --- /dev/null +++ b/SacsMobileMaui/Maui/Utils/SamThreadUtil.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Utils +{ + //======================================================================= + public static class SamThreadUtil + { + //------------------------------------------------------------------- + // Thread utilities. + //------------------------------------------------------------------- + + /// Is the current thread the main thread. + public static bool IsMainThread() + { + return MainThread.IsMainThread; + } + + //------------------------------------------------------------------- + // I n v o k e o n M a i n T h r e a d a n d W a i t + //------------------------------------------------------------------- + + /// Invoke task on main thread. + public static void InvokeOnMainThread(Action taskFn) + { + MainThread.BeginInvokeOnMainThread(() => + { + taskFn(); + }); + } + + /// Invoke task on main thread and wait for completion. + public static void InvokeOnMainThreadSync(Action taskFn) + { + var tcs = new TaskCompletionSource(); + MainThread.BeginInvokeOnMainThread(() => + { + try + { + taskFn(); + tcs.SetResult(true); + } + catch (Exception ex) { tcs.SetException(ex); } + }); + } + + /// Invoke task on main thread and wait for completion. + public static T InvokeOnMainThreadSync(Func taskFn) + { + var tcs = new TaskCompletionSource(); + MainThread.BeginInvokeOnMainThread(() => + { + try + { + var result = taskFn(); + tcs.SetResult(result); + } + catch (Exception ex) { tcs.SetException(ex); } + }); + return tcs.Task.Result; + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Utils/SamTimerUtil.cs b/SacsMobileMaui/Maui/Utils/SamTimerUtil.cs new file mode 100644 index 0000000..3669ebe --- /dev/null +++ b/SacsMobileMaui/Maui/Utils/SamTimerUtil.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static System.Net.Mime.MediaTypeNames; + +namespace Sarand.Net.Mobile.Maui.Utils +{ + //======================================================================= + public static class SamTimerUtil + { + //------------------------------------------------------------------- + // Timer utilities. + //------------------------------------------------------------------- + + public static IDispatcherTimer DoTimer (BindableObject bindable, TimeSpan interval, bool isRepeating, EventHandler handler) + { + IDispatcherTimer timer = bindable.Dispatcher.CreateTimer(); + timer.Interval = interval; + timer.IsRepeating = isRepeating; + timer.Tick += handler; + timer.Start(); + return timer; + } + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Views/ISamView.cs b/SacsMobileMaui/Maui/Views/ISamView.cs new file mode 100644 index 0000000..a4e62b8 --- /dev/null +++ b/SacsMobileMaui/Maui/Views/ISamView.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Views +{ + //====================================================================== + public interface ISamView + { + //------------------------------------------------------------------- + + /// + /// Configure layout of components when visual properties (eg. change in orientation) occurs. + /// Automatically called by parent page when dimensions change. + /// NB Not to be used for initial population of components as this method may be called multiple times. + /// + void ConfigureComponents(); + + void SetControlActivity(); + + void SetControlsReadOnly(); + + //------------------------------------------------------------------- + } + //====================================================================== +} diff --git a/SacsMobileMaui/Maui/Views/SamBorder.cs b/SacsMobileMaui/Maui/Views/SamBorder.cs new file mode 100644 index 0000000..cd45971 --- /dev/null +++ b/SacsMobileMaui/Maui/Views/SamBorder.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Views +{ + //======================================================================= + public class SamBorder : Border + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + + //------------------------------------------------------------------- + // Construction. + public SamBorder() + { + } + + //------------------------------------------------------------------- + // Properties. + + //------------------------------------------------------------------- + // Configure components. + public virtual void ConfigureComponents() + { + } + + //------------------------------------------------------------------- + // Control activity. + public virtual void SetControlActivity() + { + SetControlsReadOnly(); + } + public virtual void SetControlsReadOnly() + { + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Views/SamBoxView.cs b/SacsMobileMaui/Maui/Views/SamBoxView.cs new file mode 100644 index 0000000..1eb952b --- /dev/null +++ b/SacsMobileMaui/Maui/Views/SamBoxView.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Views +{ + //======================================================================= + public class SamBoxView : BoxView, ISamView + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + + //------------------------------------------------------------------- + // Construction. + public SamBoxView() + { + } + + //------------------------------------------------------------------- + // Properties. + + //------------------------------------------------------------------- + // Configure components. + public virtual void ConfigureComponents() + { + } + + //------------------------------------------------------------------- + // Control activity. + public virtual void SetControlActivity() + { + SetControlsReadOnly(); + } + public virtual void SetControlsReadOnly() + { + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Views/SamContentView.cs b/SacsMobileMaui/Maui/Views/SamContentView.cs new file mode 100644 index 0000000..45fbf2c --- /dev/null +++ b/SacsMobileMaui/Maui/Views/SamContentView.cs @@ -0,0 +1,70 @@ +using Sarand.Net.Mobile.Maui.Utils; +using Sarand.Net.Standard.Base.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Views +{ + //======================================================================= + public class SamContentView : ContentView, ISamView + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + private bool readOnly = false; + + //------------------------------------------------------------------- + // Construction. + public SamContentView() + { + } + + //------------------------------------------------------------------- + // Properties. + + public Page? GetPage() { return SamElementUtil.GetPage(this); } + + public bool ReadOnly + { + get { return readOnly; } + set { if (readOnly == value) return; readOnly = value; SetControlActivity(); } + } + + //------------------------------------------------------------------- + // Configure components. + public virtual void ConfigureComponents() + { + } + + //------------------------------------------------------------------- + // Control activity. + public virtual void SetControlActivity() + { + SetControlsReadOnly(); + } + public virtual void SetControlsReadOnly() + { + } + + //------------------------------------------------------------------- + // View events. + + protected override void OnPropertyChanged([CallerMemberName] string propertyName = "") + { + base.OnPropertyChanged(propertyName); + if (propertyName.EqualsCI(IsEnabledProperty.PropertyName)) + { + SetControlActivity(); + } + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Views/SamFrame.cs b/SacsMobileMaui/Maui/Views/SamFrame.cs new file mode 100644 index 0000000..49b9c59 --- /dev/null +++ b/SacsMobileMaui/Maui/Views/SamFrame.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Views +{ + //======================================================================= + public class SamFrame : Frame, ISamView + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + + //------------------------------------------------------------------- + // Construction. + public SamFrame() + { + } + + //------------------------------------------------------------------- + // Properties. + + //------------------------------------------------------------------- + // Configure components. + public virtual void ConfigureComponents() + { + } + + //------------------------------------------------------------------- + // Control activity. + public virtual void SetControlActivity() + { + SetControlsReadOnly(); + } + public virtual void SetControlsReadOnly() + { + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Maui/Views/SamView.cs b/SacsMobileMaui/Maui/Views/SamView.cs new file mode 100644 index 0000000..11ef025 --- /dev/null +++ b/SacsMobileMaui/Maui/Views/SamView.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Mobile.Maui.Views +{ + //======================================================================= + public class SamView : View, ISamView + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + + //------------------------------------------------------------------- + // Construction. + public SamView() + { + } + + //------------------------------------------------------------------- + // Properties. + + //------------------------------------------------------------------- + // Configure components. + public virtual void ConfigureComponents() + { + } + + //------------------------------------------------------------------- + // Control activity. + public virtual void SetControlActivity() + { + SetControlsReadOnly(); + } + public virtual void SetControlsReadOnly() + { + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsMobileMaui/Platforms/Android/PlatformClass1.cs b/SacsMobileMaui/Platforms/Android/PlatformClass1.cs new file mode 100644 index 0000000..217dd04 --- /dev/null +++ b/SacsMobileMaui/Platforms/Android/PlatformClass1.cs @@ -0,0 +1,7 @@ +namespace SacsMobileMaui +{ + // All the code in this file is only included on Android. + public class PlatformClass1 + { + } +} diff --git a/SacsMobileMaui/Platforms/MacCatalyst/PlatformClass1.cs b/SacsMobileMaui/Platforms/MacCatalyst/PlatformClass1.cs new file mode 100644 index 0000000..caa7f97 --- /dev/null +++ b/SacsMobileMaui/Platforms/MacCatalyst/PlatformClass1.cs @@ -0,0 +1,7 @@ +namespace SacsMobileMaui +{ + // All the code in this file is only included on Mac Catalyst. + public class PlatformClass1 + { + } +} diff --git a/SacsMobileMaui/Platforms/Tizen/PlatformClass1.cs b/SacsMobileMaui/Platforms/Tizen/PlatformClass1.cs new file mode 100644 index 0000000..1ba08e1 --- /dev/null +++ b/SacsMobileMaui/Platforms/Tizen/PlatformClass1.cs @@ -0,0 +1,9 @@ +using System; + +namespace SacsMobileMaui +{ + // All the code in this file is only included on Tizen. + public class PlatformClass1 + { + } +} \ No newline at end of file diff --git a/SacsMobileMaui/Platforms/Windows/PlatformClass1.cs b/SacsMobileMaui/Platforms/Windows/PlatformClass1.cs new file mode 100644 index 0000000..48ff4d1 --- /dev/null +++ b/SacsMobileMaui/Platforms/Windows/PlatformClass1.cs @@ -0,0 +1,7 @@ +namespace SacsMobileMaui +{ + // All the code in this file is only included on Windows. + public class PlatformClass1 + { + } +} diff --git a/SacsMobileMaui/Platforms/iOS/PlatformClass1.cs b/SacsMobileMaui/Platforms/iOS/PlatformClass1.cs new file mode 100644 index 0000000..c3df60d --- /dev/null +++ b/SacsMobileMaui/Platforms/iOS/PlatformClass1.cs @@ -0,0 +1,7 @@ +namespace SacsMobileMaui +{ + // All the code in this file is only included on iOS. + public class PlatformClass1 + { + } +} diff --git a/SacsMobileMaui/SacsMobileMaui.csproj b/SacsMobileMaui/SacsMobileMaui.csproj new file mode 100644 index 0000000..3def31e --- /dev/null +++ b/SacsMobileMaui/SacsMobileMaui.csproj @@ -0,0 +1,32 @@ + + + + net8.0-android;net8.0-ios;net8.0-maccatalyst + $(TargetFrameworks);net8.0-windows10.0.19041.0 + + + true + true + enable + enable + + 15.4 + 13.1 + 21.0 + 10.0.17763.0 + 10.0.17763.0 + 6.3 + Sarand.Net.Mobile + + + + + + + + + + + + + diff --git a/SacsStandardMob/SacsStandardMob.csproj b/SacsMobileXamarin/SacsMobileXamarin.csproj similarity index 88% rename from SacsStandardMob/SacsStandardMob.csproj rename to SacsMobileXamarin/SacsMobileXamarin.csproj index 82045e8..a74f7c4 100644 --- a/SacsStandardMob/SacsStandardMob.csproj +++ b/SacsMobileXamarin/SacsMobileXamarin.csproj @@ -2,7 +2,7 @@ net6.0 - Sarand.Net.Standard + Sarand.Net.Mobile diff --git a/SacsStandardMob/Mobile/App/SaxApplication.cs b/SacsMobileXamarin/Xamarin/App/SaxApplication.cs similarity index 97% rename from SacsStandardMob/Mobile/App/SaxApplication.cs rename to SacsMobileXamarin/Xamarin/App/SaxApplication.cs index 058ddd3..a0a3ada 100644 --- a/SacsStandardMob/Mobile/App/SaxApplication.cs +++ b/SacsMobileXamarin/Xamarin/App/SaxApplication.cs @@ -6,7 +6,7 @@ using System.Text; using Xamarin.Essentials; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.App +namespace Sarand.Net.Mobile.Xamarin.App { //======================================================================= public abstract class SaxApplication : Application @@ -36,6 +36,7 @@ namespace Sarand.Net.Standard.Mobile.App //------------------------------------------------------------------- // Properties. + // Device screen size and orientation. public static bool Landscape => DeviceWidth > DeviceHeight; public static double DeviceWidth => DeviceDisplay.MainDisplayInfo.Width; diff --git a/SacsStandardMob/Mobile/Forms/Base/SaxComponents.cs b/SacsMobileXamarin/Xamarin/Forms/Base/SaxComponents.cs similarity index 96% rename from SacsStandardMob/Mobile/Forms/Base/SaxComponents.cs rename to SacsMobileXamarin/Xamarin/Forms/Base/SaxComponents.cs index 68f4bb3..f8d03bb 100644 --- a/SacsStandardMob/Mobile/Forms/Base/SaxComponents.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Base/SaxComponents.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Base +namespace Sarand.Net.Mobile.Xamarin.Forms.Base { //======================================================================= public class SaxComponents diff --git a/SacsStandardMob/Mobile/Forms/Controls/SaxButton.cs b/SacsMobileXamarin/Xamarin/Forms/Controls/SaxButton.cs similarity index 95% rename from SacsStandardMob/Mobile/Forms/Controls/SaxButton.cs rename to SacsMobileXamarin/Xamarin/Forms/Controls/SaxButton.cs index 486cff5..ba8399e 100644 --- a/SacsStandardMob/Mobile/Forms/Controls/SaxButton.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Controls/SaxButton.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Controls +namespace Sarand.Net.Mobile.Xamarin.Forms.Controls { //======================================================================= public class SaxButton : Button diff --git a/SacsStandardMob/Mobile/Forms/Controls/SaxDatePicker.cs b/SacsMobileXamarin/Xamarin/Forms/Controls/SaxDatePicker.cs similarity index 97% rename from SacsStandardMob/Mobile/Forms/Controls/SaxDatePicker.cs rename to SacsMobileXamarin/Xamarin/Forms/Controls/SaxDatePicker.cs index deef295..2acf056 100644 --- a/SacsStandardMob/Mobile/Forms/Controls/SaxDatePicker.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Controls/SaxDatePicker.cs @@ -1,13 +1,13 @@ using Sarand.Net.Standard.Base.Core; using Sarand.Net.Standard.Base.Utils; -using Sarand.Net.Standard.Mobile.Forms.Layouts; -using Sarand.Net.Standard.Mobile.Forms.Views; +using Sarand.Net.Mobile.Xamarin.Forms.Layouts; +using Sarand.Net.Mobile.Xamarin.Forms.Views; using System; using System.Collections.Generic; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Controls +namespace Sarand.Net.Mobile.Xamarin.Forms.Controls { //======================================================================= public class SaxDatePicker : SaxContentView diff --git a/SacsStandardMob/Mobile/Forms/Controls/SaxDateTimePicker.cs b/SacsMobileXamarin/Xamarin/Forms/Controls/SaxDateTimePicker.cs similarity index 96% rename from SacsStandardMob/Mobile/Forms/Controls/SaxDateTimePicker.cs rename to SacsMobileXamarin/Xamarin/Forms/Controls/SaxDateTimePicker.cs index 8d84d16..d262345 100644 --- a/SacsStandardMob/Mobile/Forms/Controls/SaxDateTimePicker.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Controls/SaxDateTimePicker.cs @@ -1,14 +1,14 @@ using Sarand.Net.Standard.Base.Core; using Sarand.Net.Standard.Base.Utils; -using Sarand.Net.Standard.Mobile.Forms.Layouts; -using Sarand.Net.Standard.Mobile.Forms.Views; +using Sarand.Net.Mobile.Xamarin.Forms.Layouts; +using Sarand.Net.Mobile.Xamarin.Forms.Views; using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Controls +namespace Sarand.Net.Mobile.Xamarin.Forms.Controls { //======================================================================= public class SaxDateTimePicker : SaxContentView @@ -16,7 +16,7 @@ namespace Sarand.Net.Standard.Mobile.Forms.Controls //------------------------------------------------------------------- // Definitions. // Control layout. - private SaxStackLayout layoutControl = new SaxStackLayout() { Orientation = Xamarin.Forms.StackOrientation.Horizontal }; + private SaxStackLayout layoutControl = new SaxStackLayout() { Orientation = StackOrientation.Horizontal }; private SaxDatePicker pickerDate = new SaxDatePicker(); private SaxLabel labelTimePrefix = new SaxLabel(); private SaxTimePicker pickerTime = new SaxTimePicker(); diff --git a/SacsStandardMob/Mobile/Forms/Controls/SaxEditor.cs b/SacsMobileXamarin/Xamarin/Forms/Controls/SaxEditor.cs similarity index 97% rename from SacsStandardMob/Mobile/Forms/Controls/SaxEditor.cs rename to SacsMobileXamarin/Xamarin/Forms/Controls/SaxEditor.cs index 9411135..5ce3952 100644 --- a/SacsStandardMob/Mobile/Forms/Controls/SaxEditor.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Controls/SaxEditor.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Controls +namespace Sarand.Net.Mobile.Xamarin.Forms.Controls { //======================================================================= public class SaxEditor : Editor diff --git a/SacsStandardMob/Mobile/Forms/Controls/SaxEntry.cs b/SacsMobileXamarin/Xamarin/Forms/Controls/SaxEntry.cs similarity index 98% rename from SacsStandardMob/Mobile/Forms/Controls/SaxEntry.cs rename to SacsMobileXamarin/Xamarin/Forms/Controls/SaxEntry.cs index 24296b9..833457e 100644 --- a/SacsStandardMob/Mobile/Forms/Controls/SaxEntry.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Controls/SaxEntry.cs @@ -7,7 +7,7 @@ using System.Globalization; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Controls +namespace Sarand.Net.Mobile.Xamarin.Forms.Controls { //======================================================================= public class SaxEntry : Entry diff --git a/SacsStandardMob/Mobile/Forms/Controls/SaxImageButton.cs b/SacsMobileXamarin/Xamarin/Forms/Controls/SaxImageButton.cs similarity index 94% rename from SacsStandardMob/Mobile/Forms/Controls/SaxImageButton.cs rename to SacsMobileXamarin/Xamarin/Forms/Controls/SaxImageButton.cs index f57c429..271d43a 100644 --- a/SacsStandardMob/Mobile/Forms/Controls/SaxImageButton.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Controls/SaxImageButton.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Controls +namespace Sarand.Net.Mobile.Xamarin.Forms.Controls { //======================================================================= public class SaxImageButton : ImageButton diff --git a/SacsStandardMob/Mobile/Forms/Controls/SaxLabel.cs b/SacsMobileXamarin/Xamarin/Forms/Controls/SaxLabel.cs similarity index 95% rename from SacsStandardMob/Mobile/Forms/Controls/SaxLabel.cs rename to SacsMobileXamarin/Xamarin/Forms/Controls/SaxLabel.cs index 78025f7..94eed65 100644 --- a/SacsStandardMob/Mobile/Forms/Controls/SaxLabel.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Controls/SaxLabel.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Controls +namespace Sarand.Net.Mobile.Xamarin.Forms.Controls { //======================================================================= public class SaxLabel : Label diff --git a/SacsStandardMob/Mobile/Forms/Controls/SaxPicker.cs b/SacsMobileXamarin/Xamarin/Forms/Controls/SaxPicker.cs similarity index 89% rename from SacsStandardMob/Mobile/Forms/Controls/SaxPicker.cs rename to SacsMobileXamarin/Xamarin/Forms/Controls/SaxPicker.cs index bac500f..7d8dc5a 100644 --- a/SacsStandardMob/Mobile/Forms/Controls/SaxPicker.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Controls/SaxPicker.cs @@ -6,14 +6,14 @@ using System.Text; using Xamarin.Forms; using Sarand.Net.Standard.Base.Utils; -namespace Sarand.Net.Standard.Mobile.Forms.Controls +namespace Sarand.Net.Mobile.Xamarin.Forms.Controls { //======================================================================= public class SaxPicker : Picker { //------------------------------------------------------------------- // Definitions. - public class SlmPickerItem + public class SaxPickerItem { public SysId Id { get; set; } = new SysId(); public String Code { get; set; } = ""; @@ -27,7 +27,7 @@ namespace Sarand.Net.Standard.Mobile.Forms.Controls //------------------------------------------------------------------- // Data members. - private readonly List pickerItems = new List(); + private readonly List pickerItems = new List(); //------------------------------------------------------------------- // Construction. @@ -69,7 +69,7 @@ namespace Sarand.Net.Standard.Mobile.Forms.Controls pickerItems.Clear(); } /// Replace existing picker item list. - public void SetItems (List pickerItems) + public void SetItems (List pickerItems) { ClearItems(); this.pickerItems.AddRange(pickerItems); @@ -83,7 +83,7 @@ namespace Sarand.Net.Standard.Mobile.Forms.Controls public bool AddItem (SysId id, String caption) { if (ContainsItemId(id)) return false; - pickerItems.Add(new SlmPickerItem() { Id = id, Caption = caption }); + pickerItems.Add(new SaxPickerItem() { Id = id, Caption = caption }); RefreshPickerItems(); return ContainsItemId(id); } @@ -94,7 +94,7 @@ namespace Sarand.Net.Standard.Mobile.Forms.Controls public bool AddItem (String code, String caption) { if (ContainsItemCode(code)) return false; - pickerItems.Add(new SlmPickerItem() { Code = code, Caption = caption }); + pickerItems.Add(new SaxPickerItem() { Code = code, Caption = caption }); RefreshPickerItems(); return ContainsItemCode(code); } @@ -112,13 +112,13 @@ namespace Sarand.Net.Standard.Mobile.Forms.Controls //------------------------------------------------------------------- // I t e m S e l e c t i o n //------------------------------------------------------------------- - public SlmPickerItem SelectedPickerItem + public SaxPickerItem SelectedPickerItem { get { object selectedItem = SelectedItem; - if (selectedItem == null || !(selectedItem is SlmPickerItem)) return null; - return (selectedItem as SlmPickerItem); + if (selectedItem == null || !(selectedItem is SaxPickerItem)) return null; + return (selectedItem as SaxPickerItem); } set { @@ -131,7 +131,7 @@ namespace Sarand.Net.Standard.Mobile.Forms.Controls { get { - SlmPickerItem selectedPickerItem = SelectedPickerItem; + SaxPickerItem selectedPickerItem = SelectedPickerItem; return selectedPickerItem != null ? selectedPickerItem.Id : new SysId(); } set @@ -143,7 +143,7 @@ namespace Sarand.Net.Standard.Mobile.Forms.Controls { get { - SlmPickerItem selectedPickerItem = SelectedPickerItem; + SaxPickerItem selectedPickerItem = SelectedPickerItem; return selectedPickerItem != null ? selectedPickerItem.Code : ""; } set diff --git a/SacsStandardMob/Mobile/Forms/Controls/SaxTabControl.cs b/SacsMobileXamarin/Xamarin/Forms/Controls/SaxTabControl.cs similarity index 97% rename from SacsStandardMob/Mobile/Forms/Controls/SaxTabControl.cs rename to SacsMobileXamarin/Xamarin/Forms/Controls/SaxTabControl.cs index d5a13d8..cbb9029 100644 --- a/SacsStandardMob/Mobile/Forms/Controls/SaxTabControl.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Controls/SaxTabControl.cs @@ -1,12 +1,12 @@ -using Sarand.Net.Standard.Mobile.Forms.Layouts; -using Sarand.Net.Standard.Mobile.Forms.Panels; -using Sarand.Net.Standard.Mobile.Forms.Views; +using Sarand.Net.Mobile.Xamarin.Forms.Layouts; +using Sarand.Net.Mobile.Xamarin.Forms.Panels; +using Sarand.Net.Mobile.Xamarin.Forms.Views; using System; using System.Collections.Generic; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Controls +namespace Sarand.Net.Mobile.Xamarin.Forms.Controls { //======================================================================= public class SaxTabControl : ContentView diff --git a/SacsStandardMob/Mobile/Forms/Controls/SaxTimePicker.cs b/SacsMobileXamarin/Xamarin/Forms/Controls/SaxTimePicker.cs similarity index 97% rename from SacsStandardMob/Mobile/Forms/Controls/SaxTimePicker.cs rename to SacsMobileXamarin/Xamarin/Forms/Controls/SaxTimePicker.cs index f5ad703..336b79a 100644 --- a/SacsStandardMob/Mobile/Forms/Controls/SaxTimePicker.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Controls/SaxTimePicker.cs @@ -6,7 +6,7 @@ using System.Runtime.CompilerServices; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Controls +namespace Sarand.Net.Mobile.Xamarin.Forms.Controls { //======================================================================= public class SaxTimePicker : TimePicker diff --git a/SacsStandardMob/Mobile/Forms/Controls/SaxWebView.cs b/SacsMobileXamarin/Xamarin/Forms/Controls/SaxWebView.cs similarity index 98% rename from SacsStandardMob/Mobile/Forms/Controls/SaxWebView.cs rename to SacsMobileXamarin/Xamarin/Forms/Controls/SaxWebView.cs index b2274af..693a2d9 100644 --- a/SacsStandardMob/Mobile/Forms/Controls/SaxWebView.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Controls/SaxWebView.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Controls +namespace Sarand.Net.Mobile.Xamarin.Forms.Controls { //======================================================================= public class SaxWebView : WebView diff --git a/SacsStandardMob/Mobile/Forms/Layouts/SaxAbsoluteLayout.cs b/SacsMobileXamarin/Xamarin/Forms/Layouts/SaxAbsoluteLayout.cs similarity index 93% rename from SacsStandardMob/Mobile/Forms/Layouts/SaxAbsoluteLayout.cs rename to SacsMobileXamarin/Xamarin/Forms/Layouts/SaxAbsoluteLayout.cs index e0eb29e..803cf36 100644 --- a/SacsStandardMob/Mobile/Forms/Layouts/SaxAbsoluteLayout.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Layouts/SaxAbsoluteLayout.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Layouts +namespace Sarand.Net.Mobile.Xamarin.Forms.Layouts { //======================================================================= public class SaxAbsoluteLayout : AbsoluteLayout diff --git a/SacsStandardMob/Mobile/Forms/Layouts/SaxFlexLayout.cs b/SacsMobileXamarin/Xamarin/Forms/Layouts/SaxFlexLayout.cs similarity index 93% rename from SacsStandardMob/Mobile/Forms/Layouts/SaxFlexLayout.cs rename to SacsMobileXamarin/Xamarin/Forms/Layouts/SaxFlexLayout.cs index f6698fb..38ac923 100644 --- a/SacsStandardMob/Mobile/Forms/Layouts/SaxFlexLayout.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Layouts/SaxFlexLayout.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Layouts +namespace Sarand.Net.Mobile.Xamarin.Forms.Layouts { //======================================================================= public class SaxFlexLayout : FlexLayout diff --git a/SacsMobileXamarin/Xamarin/Forms/Layouts/SaxGrid.cs b/SacsMobileXamarin/Xamarin/Forms/Layouts/SaxGrid.cs new file mode 100644 index 0000000..4096837 --- /dev/null +++ b/SacsMobileXamarin/Xamarin/Forms/Layouts/SaxGrid.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Text; +using Xamarin.Forms; + +namespace Sarand.Net.Mobile.Xamarin.Forms.Layouts +{ + //======================================================================= + public class SaxGrid : Grid + { + //------------------------------------------------------------------- + // Definitions. + + //------------------------------------------------------------------- + // Data members. + + //------------------------------------------------------------------- + // Construction. + public SaxGrid() + { + } + + //------------------------------------------------------------------- + // Properties. + + //------------------------------------------------------------------- + // G r i d E v e n t s + //------------------------------------------------------------------- + protected override void OnParentSet() + { + base.OnParentSet(); + } + //------------------------------------------------------------------- + protected override void OnPropertyChanging([CallerMemberName] string propertyName = null) + { + base.OnPropertyChanging(propertyName); + } + protected override void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + base.OnPropertyChanged(propertyName); + } + //------------------------------------------------------------------- + protected override void OnAdded(View view) + { + base.OnAdded(view); + } + protected override void OnChildAdded(Element child) + { + base.OnChildAdded(child); + } + //------------------------------------------------------------------- + protected override void OnRemoved(View view) + { + base.OnRemoved(view); + } + [Obsolete("OnChildRemoved(Element) is obsolete as of version 4.8.0. Please use OnChildRemoved(Element, int) instead.")] + protected override void OnChildRemoved(Element child) + { + base.OnChildRemoved(child); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsStandardMob/Mobile/Forms/Layouts/SaxStackLayout.cs b/SacsMobileXamarin/Xamarin/Forms/Layouts/SaxStackLayout.cs similarity index 93% rename from SacsStandardMob/Mobile/Forms/Layouts/SaxStackLayout.cs rename to SacsMobileXamarin/Xamarin/Forms/Layouts/SaxStackLayout.cs index 8e0e731..6d3db61 100644 --- a/SacsStandardMob/Mobile/Forms/Layouts/SaxStackLayout.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Layouts/SaxStackLayout.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Layouts +namespace Sarand.Net.Mobile.Xamarin.Forms.Layouts { //======================================================================= public class SaxStackLayout : StackLayout diff --git a/SacsStandardMob/Mobile/Forms/Layouts/SaxWrapLayout.cs b/SacsMobileXamarin/Xamarin/Forms/Layouts/SaxWrapLayout.cs similarity index 99% rename from SacsStandardMob/Mobile/Forms/Layouts/SaxWrapLayout.cs rename to SacsMobileXamarin/Xamarin/Forms/Layouts/SaxWrapLayout.cs index aa7e9ef..9cfb9a4 100644 --- a/SacsStandardMob/Mobile/Forms/Layouts/SaxWrapLayout.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Layouts/SaxWrapLayout.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Layouts +namespace Sarand.Net.Mobile.Xamarin.Forms.Layouts { //======================================================================= /// diff --git a/SacsStandardMob/Mobile/Forms/Pages/SaxContentPage.cs b/SacsMobileXamarin/Xamarin/Forms/Pages/SaxContentPage.cs similarity index 98% rename from SacsStandardMob/Mobile/Forms/Pages/SaxContentPage.cs rename to SacsMobileXamarin/Xamarin/Forms/Pages/SaxContentPage.cs index 98a6cc2..32fda18 100644 --- a/SacsStandardMob/Mobile/Forms/Pages/SaxContentPage.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Pages/SaxContentPage.cs @@ -8,7 +8,7 @@ using System.Text; using System.Threading.Tasks; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Pages +namespace Sarand.Net.Mobile.Xamarin.Forms.Pages { //======================================================================= public abstract class SaxContentPage : ContentPage diff --git a/SacsStandardMob/Mobile/Forms/Panels/SaxPanel.cs b/SacsMobileXamarin/Xamarin/Forms/Panels/SaxPanel.cs similarity index 96% rename from SacsStandardMob/Mobile/Forms/Panels/SaxPanel.cs rename to SacsMobileXamarin/Xamarin/Forms/Panels/SaxPanel.cs index 63a01a2..5986846 100644 --- a/SacsStandardMob/Mobile/Forms/Panels/SaxPanel.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Panels/SaxPanel.cs @@ -1,4 +1,4 @@ -using Sarand.Net.Standard.Mobile.Forms.Views; +using Sarand.Net.Mobile.Xamarin.Forms.Views; using System; using System.Collections.Generic; using System.Linq; @@ -7,7 +7,7 @@ using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Panels +namespace Sarand.Net.Mobile.Xamarin.Forms.Panels { //======================================================================= public class SaxPanel : SaxContentView diff --git a/SacsStandardMob/Mobile/Forms/Panels/SaxPanel_ItemFilter.cs b/SacsMobileXamarin/Xamarin/Forms/Panels/SaxPanel_ItemFilter.cs similarity index 97% rename from SacsStandardMob/Mobile/Forms/Panels/SaxPanel_ItemFilter.cs rename to SacsMobileXamarin/Xamarin/Forms/Panels/SaxPanel_ItemFilter.cs index b815308..ce10db9 100644 --- a/SacsStandardMob/Mobile/Forms/Panels/SaxPanel_ItemFilter.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Panels/SaxPanel_ItemFilter.cs @@ -1,12 +1,11 @@ -using Sarand.Net.Standard.Mobile.Forms.Controls; -using Sarand.Net.Standard.Mobile.Forms.Layouts; -using Sarand.Net.Standard.Mobile.Forms.Templates; +using Sarand.Net.Mobile.Xamarin.Forms.Controls; +using Sarand.Net.Mobile.Xamarin.Forms.Layouts; using System; using System.Collections.Generic; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Panels +namespace Sarand.Net.Mobile.Xamarin.Forms.Panels { //======================================================================= public class SacsFilterPropertyType diff --git a/SacsStandardMob/Mobile/Forms/Panels/SaxPanel_ItemFilterProperty.cs b/SacsMobileXamarin/Xamarin/Forms/Panels/SaxPanel_ItemFilterProperty.cs similarity index 95% rename from SacsStandardMob/Mobile/Forms/Panels/SaxPanel_ItemFilterProperty.cs rename to SacsMobileXamarin/Xamarin/Forms/Panels/SaxPanel_ItemFilterProperty.cs index c986b14..9d89c14 100644 --- a/SacsStandardMob/Mobile/Forms/Panels/SaxPanel_ItemFilterProperty.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Panels/SaxPanel_ItemFilterProperty.cs @@ -1,16 +1,16 @@ using Sarand.Net.Standard.Base.Core; using Sarand.Net.Standard.Base.Utils; -using Sarand.Net.Standard.Mobile.Forms.Controls; -using Sarand.Net.Standard.Mobile.Forms.Templates; +using Sarand.Net.Mobile.Xamarin.Forms.Controls; using System; using System.Collections.Generic; using System.Text; using Xamarin.Forms; +using Sarand.Net.Mobile.Xamarin.Forms.Layouts; -namespace Sarand.Net.Standard.Mobile.Forms.Panels +namespace Sarand.Net.Mobile.Xamarin.Forms.Panels { - //======================================================================= - public class SaxPanel_ItemFilterProperty : SaxPanel + //======================================================================= + public class SaxPanel_ItemFilterProperty : SaxPanel { //------------------------------------------------------------------- // Definitions. diff --git a/SacsStandardMob/Mobile/Forms/Panels/SaxPanel_ItemListHeader.cs b/SacsMobileXamarin/Xamarin/Forms/Panels/SaxPanel_ItemListHeader.cs similarity index 85% rename from SacsStandardMob/Mobile/Forms/Panels/SaxPanel_ItemListHeader.cs rename to SacsMobileXamarin/Xamarin/Forms/Panels/SaxPanel_ItemListHeader.cs index c034171..b18a45e 100644 --- a/SacsStandardMob/Mobile/Forms/Panels/SaxPanel_ItemListHeader.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Panels/SaxPanel_ItemListHeader.cs @@ -3,16 +3,16 @@ using Sarand.Net.Standard.Base.Core; using Sarand.Net.Standard.Base.Dbas; using Sarand.Net.Standard.Base.Helpers; using Sarand.Net.Standard.Base.Utils; -using Sarand.Net.Standard.Mobile.Forms.Controls; -using Sarand.Net.Standard.Mobile.Forms.Layouts; -using Sarand.Net.Standard.Mobile.Forms.Views; -using Sarand.Net.Standard.Mobile.Utils; +using Sarand.Net.Mobile.Xamarin.Forms.Controls; +using Sarand.Net.Mobile.Xamarin.Forms.Layouts; +using Sarand.Net.Mobile.Xamarin.Forms.Views; +using Sarand.Net.Mobile.Xamarin.Utils; using System; using System.Collections.Generic; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Panels +namespace Sarand.Net.Mobile.Xamarin.Forms.Panels { //======================================================================= public class SaxPanel_ItemListHeader : SaxPanel @@ -21,7 +21,7 @@ namespace Sarand.Net.Standard.Mobile.Forms.Panels // Definitions. public class Config { - public Thickness Margin { get; set; } = new Thickness(0, 0, 0, 8); + public Thickness? Margin { get; set; } = new Thickness(0, 0, 0, 8); public String Caption { get; set; } public double HeaderBorderWidth { get; set; } = 4.0; public float HeaderBorderRadius { get; set; } = 8.0f; @@ -31,7 +31,7 @@ namespace Sarand.Net.Standard.Mobile.Forms.Panels // Styling. public double CaptionLabelFontSizeRatio { get; set; } = 1.0; public double PagingLabelFontSizeRatio { get; set; } = 1.0; - public Thickness LabelMargin { get; set; } + public Thickness? LabelMargin { get; set; } = null; // Paging controls. public static int PagingButtonWidthMin { get; } = 40; public static int PagingButtonWidthMax { get; } = 64; @@ -51,10 +51,10 @@ namespace Sarand.Net.Standard.Mobile.Forms.Panels private Config config; // Layout. private SaxFrame frame = new SaxFrame(); - private SaxStackLayout mainLayout = new SaxStackLayout() { Orientation=StackOrientation.Vertical }; + private SaxStackLayout mainLayout = new SaxStackLayout() { Orientation = StackOrientation.Vertical }; // Header. private SaxWrapLayout headerLayout = new SaxWrapLayout() { SpacingX = 8.0 }; - private SaxContentView captionLabelView = new SaxContentView(); + private SaxContentView captionLabelView = new SaxContentView(); private SaxLabel labelCaption = new SaxLabel() { Text = "" }; private double initialLabelFontSize = 0; // Paging. @@ -65,16 +65,16 @@ namespace Sarand.Net.Standard.Mobile.Forms.Panels public override bool Paged { get { return base.Paged && TotalItems > 0; } } } private readonly PagingData paging = new PagingData(); - private SaxStackLayout pagingStack = new SaxStackLayout() { Orientation=StackOrientation.Horizontal }; + private SaxStackLayout pagingStack = new SaxStackLayout() { Orientation = StackOrientation.Horizontal }; private SaxLabel labelPaging = new SaxLabel() { Text = "[Paging]" }; - private SaxImageButton buttonPagingFirst = new SaxImageButton() { WidthRequest = 32, HeightRequest = 32, Aspect = Aspect.AspectFit, Padding = new Thickness(2,4), BackgroundColor = Color.Transparent }; - private SaxImageButton buttonPagingPrev = new SaxImageButton() { WidthRequest = 32, HeightRequest = 32, Aspect = Aspect.AspectFit, Padding = new Thickness(2,4), BackgroundColor = Color.Transparent }; - private SaxImageButton buttonPagingNext = new SaxImageButton() { WidthRequest = 32, HeightRequest = 32, Aspect = Aspect.AspectFit, Padding = new Thickness(2,4), BackgroundColor = Color.Transparent }; - private SaxImageButton buttonPagingLast = new SaxImageButton() { WidthRequest = 32, HeightRequest = 32, Aspect = Aspect.AspectFit, Padding = new Thickness(2,4), BackgroundColor = Color.Transparent }; + private SaxImageButton buttonPagingFirst = new SaxImageButton() { WidthRequest = 32, HeightRequest = 32, Aspect = Aspect.AspectFit, Padding = new Thickness(2, 4), BackgroundColor = Color.Transparent }; + private SaxImageButton buttonPagingPrev = new SaxImageButton() { WidthRequest = 32, HeightRequest = 32, Aspect = Aspect.AspectFit, Padding = new Thickness(2, 4), BackgroundColor = Color.Transparent }; + private SaxImageButton buttonPagingNext = new SaxImageButton() { WidthRequest = 32, HeightRequest = 32, Aspect = Aspect.AspectFit, Padding = new Thickness(2, 4), BackgroundColor = Color.Transparent }; + private SaxImageButton buttonPagingLast = new SaxImageButton() { WidthRequest = 32, HeightRequest = 32, Aspect = Aspect.AspectFit, Padding = new Thickness(2, 4), BackgroundColor = Color.Transparent }; //------------------------------------------------------------------- // Construction. - public SaxPanel_ItemListHeader (Config config) + public SaxPanel_ItemListHeader(Config config) { this.config = config; initialLabelFontSize = labelCaption.FontSize; @@ -93,7 +93,7 @@ namespace Sarand.Net.Standard.Mobile.Forms.Panels //------------------------------------------------------------------- // I n i t i a l i s e //------------------------------------------------------------------- - private void InitialiseComponents () + private void InitialiseComponents() { // Frame - to allow rounded corners. Content = frame; @@ -138,7 +138,7 @@ namespace Sarand.Net.Standard.Mobile.Forms.Panels ConfigurePanel(); } - private void LabelCaption_PropertyChanging (object sender, PropertyChangingEventArgs e) + private void LabelCaption_PropertyChanging(object sender, PropertyChangingEventArgs e) { if (e.PropertyName.EqualsCI("Height")) { @@ -148,9 +148,10 @@ namespace Sarand.Net.Standard.Mobile.Forms.Panels //------------------------------------------------------------------- // C o n f i g u r e P a n e l //------------------------------------------------------------------- - private void ConfigurePanel () + private void ConfigurePanel() { - frame.Margin = config.Margin; + if (config.Margin != null) + frame.Margin = (Thickness)config.Margin; // Header. labelCaption.Text = StringUtil.EmptyOnNull(config.Caption); @@ -164,21 +165,21 @@ namespace Sarand.Net.Standard.Mobile.Forms.Panels labelPaging.FontSize = initialLabelFontSize * config.PagingLabelFontSizeRatio; if (config.LabelMargin != null) { - labelCaption.Margin = config.LabelMargin; - labelPaging.Margin = config.LabelMargin; + labelCaption.Margin = (Thickness)config.LabelMargin; + labelPaging.Margin = (Thickness)config.LabelMargin; } // Paging controls. - buttonPagingFirst.Source = SacsImageUtils.GetImageFromByteArray(SacsResourceHelper.GetImageResource(SacsResourceHelper.ImageResource.Arrow_Left_Double_Black_24_png)); + buttonPagingFirst.Source = SacsImageUtils.GetImageFromByteArray(SacsResourceHelper.GetResourceImage(SacsResourceHelper.ImageResource.Arrow_Left_Double_Black_24_png)); buttonPagingFirst.WidthRequest = Math.Max(Config.PagingButtonWidthMin, Math.Min(Config.PagingButtonWidthMax, config.PagingButtonWidth)); buttonPagingFirst.HeightRequest = Math.Max(Config.PagingButtonHeightMin, Math.Min(Config.PagingButtonHeightMax, config.PagingButtonHeight)); - buttonPagingPrev.Source = SacsImageUtils.GetImageFromByteArray(SacsResourceHelper.GetImageResource(SacsResourceHelper.ImageResource.Arrow_Left_Black_24_png)); + buttonPagingPrev.Source = SacsImageUtils.GetImageFromByteArray(SacsResourceHelper.GetResourceImage(SacsResourceHelper.ImageResource.Arrow_Left_Black_24_png)); buttonPagingPrev.WidthRequest = Math.Max(Config.PagingButtonWidthMin, Math.Min(Config.PagingButtonWidthMax, config.PagingButtonWidth)); buttonPagingPrev.HeightRequest = Math.Max(Config.PagingButtonHeightMin, Math.Min(Config.PagingButtonHeightMax, config.PagingButtonHeight)); - buttonPagingNext.Source = SacsImageUtils.GetImageFromByteArray(SacsResourceHelper.GetImageResource(SacsResourceHelper.ImageResource.Arrow_Right_Black_24_png)); + buttonPagingNext.Source = SacsImageUtils.GetImageFromByteArray(SacsResourceHelper.GetResourceImage(SacsResourceHelper.ImageResource.Arrow_Right_Black_24_png)); buttonPagingNext.WidthRequest = Math.Max(Config.PagingButtonWidthMin, Math.Min(Config.PagingButtonWidthMax, config.PagingButtonWidth)); buttonPagingNext.HeightRequest = Math.Max(Config.PagingButtonHeightMin, Math.Min(Config.PagingButtonHeightMax, config.PagingButtonHeight)); - buttonPagingLast.Source = SacsImageUtils.GetImageFromByteArray(SacsResourceHelper.GetImageResource(SacsResourceHelper.ImageResource.Arrow_Right_Double_Black_24_png)); + buttonPagingLast.Source = SacsImageUtils.GetImageFromByteArray(SacsResourceHelper.GetResourceImage(SacsResourceHelper.ImageResource.Arrow_Right_Double_Black_24_png)); buttonPagingLast.WidthRequest = Math.Max(Config.PagingButtonWidthMin, Math.Min(Config.PagingButtonWidthMax, config.PagingButtonWidth)); buttonPagingLast.HeightRequest = Math.Max(Config.PagingButtonHeightMin, Math.Min(Config.PagingButtonHeightMax, config.PagingButtonHeight)); RefreshPaging(); @@ -201,14 +202,14 @@ namespace Sarand.Net.Standard.Mobile.Forms.Panels //------------------------------------------------------------------- // P a g i n g //------------------------------------------------------------------- - public void SetPaging (uint pageNo, ushort pageLength, int totalItems) + public void SetPaging(uint pageNo, ushort pageLength, int totalItems) { paging.PageNo = pageNo; paging.PageLength = pageLength; paging.TotalItems = totalItems; RefreshPaging(); } - private void RefreshPaging () + private void RefreshPaging() { String pagingText = ""; Boolean paged = (paging.Paged && paging.TotalPages > 1); @@ -248,7 +249,7 @@ namespace Sarand.Net.Standard.Mobile.Forms.Panels public PagingActionType PagingActionType { get; set; } = PagingActionType.Unknown; } public event EventHandler PagingAction; - private void FirePagingActionEvent (PagingActionType pagingActionType) + private void FirePagingActionEvent(PagingActionType pagingActionType) { PagingActionEventArgs filterChangedEventArgs = new PagingActionEventArgs() { @@ -259,19 +260,19 @@ namespace Sarand.Net.Standard.Mobile.Forms.Panels //------------------------------------------------------------------- // Paging actions. - private void ButtonPagingFirst_Clicked (object sender, EventArgs e) + private void ButtonPagingFirst_Clicked(object sender, EventArgs e) { FirePagingActionEvent(PagingActionType.First); } - private void ButtonPagingPrev_Clicked (object sender, EventArgs e) + private void ButtonPagingPrev_Clicked(object sender, EventArgs e) { FirePagingActionEvent(PagingActionType.Prev); } - private void ButtonPagingNext_Clicked (object sender, EventArgs e) + private void ButtonPagingNext_Clicked(object sender, EventArgs e) { FirePagingActionEvent(PagingActionType.Next); } - private void ButtonPagingLast_Clicked (object sender, EventArgs e) + private void ButtonPagingLast_Clicked(object sender, EventArgs e) { FirePagingActionEvent(PagingActionType.Last); } diff --git a/SacsStandardMob/Mobile/Forms/Panels/SaxPanel_ItemListSummary.cs b/SacsMobileXamarin/Xamarin/Forms/Panels/SaxPanel_ItemListSummary.cs similarity index 91% rename from SacsStandardMob/Mobile/Forms/Panels/SaxPanel_ItemListSummary.cs rename to SacsMobileXamarin/Xamarin/Forms/Panels/SaxPanel_ItemListSummary.cs index 571e2e7..ea888ec 100644 --- a/SacsStandardMob/Mobile/Forms/Panels/SaxPanel_ItemListSummary.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Panels/SaxPanel_ItemListSummary.cs @@ -1,16 +1,16 @@ using Sarand.Net.Standard.Base.App; using Sarand.Net.Standard.Base.Core; using Sarand.Net.Standard.Base.Helpers; -using Sarand.Net.Standard.Mobile.Forms.Controls; -using Sarand.Net.Standard.Mobile.Forms.Layouts; -using Sarand.Net.Standard.Mobile.Forms.Views; -using Sarand.Net.Standard.Mobile.Utils; +using Sarand.Net.Mobile.Xamarin.Forms.Controls; +using Sarand.Net.Mobile.Xamarin.Forms.Layouts; +using Sarand.Net.Mobile.Xamarin.Forms.Views; +using Sarand.Net.Mobile.Xamarin.Utils; using System; using System.Collections.Generic; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Panels +namespace Sarand.Net.Mobile.Xamarin.Forms.Panels { //======================================================================= /// @@ -29,11 +29,11 @@ namespace Sarand.Net.Standard.Mobile.Forms.Panels private bool showAddButton = false; private double actionButtonSpacing = 4.0; // Panel layout. - private SaxStackLayout panelLayout = new SaxStackLayout() { Orientation = Xamarin.Forms.StackOrientation.Horizontal }; + private SaxStackLayout panelLayout = new SaxStackLayout() { Orientation = StackOrientation.Horizontal }; private SaxContentView panelMessage = new SaxContentView(); private SaxLabel labelMessage = new SaxLabel() { HorizontalOptions = LayoutOptions.Start}; // Action butons. - private SaxStackLayout panelActions = new SaxStackLayout() { Orientation = Xamarin.Forms.StackOrientation.Horizontal }; + private SaxStackLayout panelActions = new SaxStackLayout() { Orientation = StackOrientation.Horizontal }; private SaxImageButton buttonAddItem = new SaxImageButton() { IsVisible = false, HorizontalOptions = LayoutOptions.End, VerticalOptions = LayoutOptions.Start }; //------------------------------------------------------------------- @@ -61,7 +61,7 @@ namespace Sarand.Net.Standard.Mobile.Forms.Panels buttonAddItem.IsVisible = showAddButton; buttonAddItem.Padding = new Thickness(0, 0, actionButtonSpacing, 0); buttonAddItem.BackgroundColor = Color.Transparent; - buttonAddItem.Source = SacsImageUtils.GetImageFromByteArray(SacsResourceHelper.GetImageResource(SacsResourceHelper.ImageResource.IconShock_Add_Green_72_png)); + buttonAddItem.Source = SacsImageUtils.GetImageFromByteArray(SacsResourceHelper.GetResourceImage(SacsResourceHelper.ImageResource.IconShock_Add_Green_72_png)); buttonAddItem.Clicked += ButtonAddItem_Clicked; panelActions.Children.Add(buttonAddItem); } diff --git a/SacsStandardMob/Mobile/Forms/Panels/SaxPanel_Messages.cs b/SacsMobileXamarin/Xamarin/Forms/Panels/SaxPanel_Messages.cs similarity index 91% rename from SacsStandardMob/Mobile/Forms/Panels/SaxPanel_Messages.cs rename to SacsMobileXamarin/Xamarin/Forms/Panels/SaxPanel_Messages.cs index 8b717fe..2708daa 100644 --- a/SacsStandardMob/Mobile/Forms/Panels/SaxPanel_Messages.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Panels/SaxPanel_Messages.cs @@ -1,11 +1,12 @@ using Sarand.Net.Standard.Base.Core; -using Sarand.Net.Standard.Mobile.Forms.Controls; -using Sarand.Net.Standard.Mobile.Forms.Layouts; +using Sarand.Net.Mobile.Xamarin.Forms.Controls; +using Sarand.Net.Mobile.Xamarin.Forms.Layouts; using System; using System.Collections.Generic; using System.Text; +using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Panels +namespace Sarand.Net.Mobile.Xamarin.Forms.Panels { //======================================================================= public class SaxPanel_Messages : SaxPanel @@ -21,7 +22,7 @@ namespace Sarand.Net.Standard.Mobile.Forms.Panels private Config config; private readonly List messages = new List(); // Components. - private SaxStackLayout mainLayout = new SaxStackLayout() { Orientation = Xamarin.Forms.StackOrientation.Vertical }; + private SaxStackLayout mainLayout = new SaxStackLayout() { Orientation = StackOrientation.Vertical }; //------------------------------------------------------------------- // Construction. diff --git a/SacsStandardMob/Mobile/Forms/Panels/SaxPanel_Progress.cs b/SacsMobileXamarin/Xamarin/Forms/Panels/SaxPanel_Progress.cs similarity index 92% rename from SacsStandardMob/Mobile/Forms/Panels/SaxPanel_Progress.cs rename to SacsMobileXamarin/Xamarin/Forms/Panels/SaxPanel_Progress.cs index 677fb16..485a21a 100644 --- a/SacsStandardMob/Mobile/Forms/Panels/SaxPanel_Progress.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Panels/SaxPanel_Progress.cs @@ -1,15 +1,15 @@ -using Sarand.Net.Standard.Mobile.Forms.Controls; -using Sarand.Net.Standard.Mobile.Forms.Templates; -using Sarand.Net.Standard.Mobile.Forms.Views; +using Sarand.Net.Mobile.Xamarin.Forms.Controls; +using Sarand.Net.Mobile.Xamarin.Forms.Layouts; +using Sarand.Net.Mobile.Xamarin.Forms.Views; using System; using System.Collections.Generic; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Panels +namespace Sarand.Net.Mobile.Xamarin.Forms.Panels { - //======================================================================= - public class SaxPanel_Progress : SaxContentView + //======================================================================= + public class SaxPanel_Progress : SaxContentView { //------------------------------------------------------------------- // Definitions. diff --git a/SacsStandardMob/Mobile/Forms/Panels/SaxPanel_PropertySummary.cs b/SacsMobileXamarin/Xamarin/Forms/Panels/SaxPanel_PropertySummary.cs similarity index 93% rename from SacsStandardMob/Mobile/Forms/Panels/SaxPanel_PropertySummary.cs rename to SacsMobileXamarin/Xamarin/Forms/Panels/SaxPanel_PropertySummary.cs index 8f4fb33..a87ddcc 100644 --- a/SacsStandardMob/Mobile/Forms/Panels/SaxPanel_PropertySummary.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Panels/SaxPanel_PropertySummary.cs @@ -1,15 +1,15 @@ -using Sarand.Net.Standard.Mobile.Forms.Controls; -using Sarand.Net.Standard.Mobile.Forms.Templates; -using Sarand.Net.Standard.Mobile.Forms.Views; +using Sarand.Net.Mobile.Xamarin.Forms.Controls; +using Sarand.Net.Mobile.Xamarin.Forms.Layouts; +using Sarand.Net.Mobile.Xamarin.Forms.Views; using System; using System.Collections.Generic; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Panels +namespace Sarand.Net.Mobile.Xamarin.Forms.Panels { - //======================================================================= - public class SaxPanel_PropertySummary : SaxContentView + //======================================================================= + public class SaxPanel_PropertySummary : SaxContentView { //------------------------------------------------------------------- // Definitions. diff --git a/SacsStandardMob/Mobile/Forms/Panels/SaxTabPanel.cs b/SacsMobileXamarin/Xamarin/Forms/Panels/SaxTabPanel.cs similarity index 93% rename from SacsStandardMob/Mobile/Forms/Panels/SaxTabPanel.cs rename to SacsMobileXamarin/Xamarin/Forms/Panels/SaxTabPanel.cs index 712516e..fb45a10 100644 --- a/SacsStandardMob/Mobile/Forms/Panels/SaxTabPanel.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Panels/SaxTabPanel.cs @@ -1,10 +1,10 @@ -using Sarand.Net.Standard.Mobile.Forms.Views; +using Sarand.Net.Mobile.Xamarin.Forms.Views; using System; using System.Collections.Generic; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Panels +namespace Sarand.Net.Mobile.Xamarin.Forms.Panels { //======================================================================= public class SaxTabPanel : SaxPanel diff --git a/SacsStandardMob/Mobile/Forms/Utils/SaxFormsUtil.cs b/SacsMobileXamarin/Xamarin/Forms/Utils/SaxFormsUtil.cs similarity index 93% rename from SacsStandardMob/Mobile/Forms/Utils/SaxFormsUtil.cs rename to SacsMobileXamarin/Xamarin/Forms/Utils/SaxFormsUtil.cs index 56e41f3..a615a6b 100644 --- a/SacsStandardMob/Mobile/Forms/Utils/SaxFormsUtil.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Utils/SaxFormsUtil.cs @@ -1,11 +1,11 @@ -using Sarand.Net.Standard.Mobile.Tasks; +using Sarand.Net.Mobile.Xamarin.Tasks; using System; using System.Collections.Generic; using System.Text; using System.Threading.Tasks; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Utils +namespace Sarand.Net.Mobile.Xamarin.Forms.Utils { //======================================================================= public static class SaxFormsUtil diff --git a/SacsStandardMob/Mobile/Forms/Utils/SaxPageUtil.cs b/SacsMobileXamarin/Xamarin/Forms/Utils/SaxPageUtil.cs similarity index 89% rename from SacsStandardMob/Mobile/Forms/Utils/SaxPageUtil.cs rename to SacsMobileXamarin/Xamarin/Forms/Utils/SaxPageUtil.cs index 8482eac..66d8fbb 100644 --- a/SacsStandardMob/Mobile/Forms/Utils/SaxPageUtil.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Utils/SaxPageUtil.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Text; using System.Threading.Tasks; -namespace Sarand.Net.Standard.Mobile.Forms.Utils +namespace Sarand.Net.Mobile.Xamarin.Forms.Utils { //======================================================================= public static class SaxPageUtil diff --git a/SacsStandardMob/Mobile/Forms/Views/SaxBoxView.cs b/SacsMobileXamarin/Xamarin/Forms/Views/SaxBoxView.cs similarity index 93% rename from SacsStandardMob/Mobile/Forms/Views/SaxBoxView.cs rename to SacsMobileXamarin/Xamarin/Forms/Views/SaxBoxView.cs index da665f0..1917c36 100644 --- a/SacsStandardMob/Mobile/Forms/Views/SaxBoxView.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Views/SaxBoxView.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Views +namespace Sarand.Net.Mobile.Xamarin.Forms.Views { //======================================================================= public class SaxBoxView : BoxView diff --git a/SacsStandardMob/Mobile/Forms/Views/SaxContentView.cs b/SacsMobileXamarin/Xamarin/Forms/Views/SaxContentView.cs similarity index 97% rename from SacsStandardMob/Mobile/Forms/Views/SaxContentView.cs rename to SacsMobileXamarin/Xamarin/Forms/Views/SaxContentView.cs index 3b96623..7035fa7 100644 --- a/SacsStandardMob/Mobile/Forms/Views/SaxContentView.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Views/SaxContentView.cs @@ -8,7 +8,7 @@ using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Views +namespace Sarand.Net.Mobile.Xamarin.Forms.Views { //======================================================================= public class SaxContentView : ContentView diff --git a/SacsStandardMob/Mobile/Forms/Views/SaxFrame.cs b/SacsMobileXamarin/Xamarin/Forms/Views/SaxFrame.cs similarity index 93% rename from SacsStandardMob/Mobile/Forms/Views/SaxFrame.cs rename to SacsMobileXamarin/Xamarin/Forms/Views/SaxFrame.cs index 56538bf..63f665e 100644 --- a/SacsStandardMob/Mobile/Forms/Views/SaxFrame.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Views/SaxFrame.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Views +namespace Sarand.Net.Mobile.Xamarin.Forms.Views { //======================================================================= public class SaxFrame : Frame diff --git a/SacsStandardMob/Mobile/Forms/Views/SaxView.cs b/SacsMobileXamarin/Xamarin/Forms/Views/SaxView.cs similarity index 93% rename from SacsStandardMob/Mobile/Forms/Views/SaxView.cs rename to SacsMobileXamarin/Xamarin/Forms/Views/SaxView.cs index 58a3223..b419f20 100644 --- a/SacsStandardMob/Mobile/Forms/Views/SaxView.cs +++ b/SacsMobileXamarin/Xamarin/Forms/Views/SaxView.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Forms.Views +namespace Sarand.Net.Mobile.Xamarin.Forms.Views { //======================================================================= public class SaxView : View diff --git a/SacsStandardMob/Mobile/Tasks/SaxThreadUtil.cs b/SacsMobileXamarin/Xamarin/Tasks/SaxThreadUtil.cs similarity index 96% rename from SacsStandardMob/Mobile/Tasks/SaxThreadUtil.cs rename to SacsMobileXamarin/Xamarin/Tasks/SaxThreadUtil.cs index b879516..b4816c9 100644 --- a/SacsStandardMob/Mobile/Tasks/SaxThreadUtil.cs +++ b/SacsMobileXamarin/Xamarin/Tasks/SaxThreadUtil.cs @@ -4,7 +4,7 @@ using System.Text; using System.Threading.Tasks; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Tasks +namespace Sarand.Net.Mobile.Xamarin.Tasks { //======================================================================= public static class SaxThreadUtil diff --git a/SacsStandardMob/Mobile/Utils/ImageUtils.cs b/SacsMobileXamarin/Xamarin/Utils/ImageUtils.cs similarity index 94% rename from SacsStandardMob/Mobile/Utils/ImageUtils.cs rename to SacsMobileXamarin/Xamarin/Utils/ImageUtils.cs index 0cf989a..ac7fb12 100644 --- a/SacsStandardMob/Mobile/Utils/ImageUtils.cs +++ b/SacsMobileXamarin/Xamarin/Utils/ImageUtils.cs @@ -4,7 +4,7 @@ using System.IO; using System.Text; using Xamarin.Forms; -namespace Sarand.Net.Standard.Mobile.Utils +namespace Sarand.Net.Mobile.Xamarin.Utils { //======================================================================= public static class SacsImageUtils diff --git a/SacsStandardBase/Base/Helpers/SacsResourceHelper.cs b/SacsStandardBase/Base/Helpers/SacsResourceHelper.cs index 79fcaca..63ce1ad 100644 --- a/SacsStandardBase/Base/Helpers/SacsResourceHelper.cs +++ b/SacsStandardBase/Base/Helpers/SacsResourceHelper.cs @@ -45,6 +45,10 @@ namespace Sarand.Net.Standard.Base.Helpers IconShock_TrashCan_Grey_72_png, } + //------------------------------------------------------------------- + // Properties. + public static Assembly MyAssembly { get; } = typeof(SacsResourceHelper).GetTypeInfo().Assembly; + //------------------------------------------------------------------- // NB 'Properties' not available in Core .Net project. // Resources must be loaded via csproj so that they are available in the Manifest Resources: @@ -58,7 +62,7 @@ namespace Sarand.Net.Standard.Base.Helpers // // REf. https://stackoverflow.com/questions/38762368/embedded-resource-in-net-core-libraries //------------------------------------------------------------------- - public static String GetTextResource(TextResource textResource) + public static String GetResourceText(TextResource textResource) { String partialPath = ""; String resourceFilename = ""; @@ -85,18 +89,17 @@ namespace Sarand.Net.Standard.Base.Helpers resourceFilename = "jquery-ui-1.12.1.min.js"; break; } - if (!StringUtil.IsEmpty(resourceFilename)) + if (!StringUtil.IsBlank(resourceFilename)) { - var assembly = typeof(SacsResourceHelper).GetTypeInfo().Assembly; - String resourceText = GetManifestResourceAsText(assembly, partialPath, resourceFilename); - if (!StringUtil.IsEmpty(resourceText)) + String resourceText = GetManifestResourceAsText(MyAssembly, partialPath, resourceFilename); + if (!StringUtil.IsBlank(resourceText)) return resourceText; } return ""; } //------------------------------------------------------------------- - public static byte[] GetImageResource(ImageResource imageResource) + public static byte[] GetResourceImage(ImageResource imageResource) { String partialPath = ""; String resourceFilename = ""; @@ -164,10 +167,9 @@ namespace Sarand.Net.Standard.Base.Helpers break; //----------------------------------------------------------- } - if (!StringUtil.IsEmpty(resourceFilename)) + if (!StringUtil.IsBlank(resourceFilename)) { - var assembly = typeof(SacsResourceHelper).GetTypeInfo().Assembly; - byte[] resourceData = GetManifestResourceAsBinary(assembly, partialPath, resourceFilename); + byte[] resourceData = GetManifestResourceAsBinary(MyAssembly, partialPath, resourceFilename); if (resourceData != null) return resourceData; } @@ -175,11 +177,12 @@ namespace Sarand.Net.Standard.Base.Helpers } //------------------------------------------------------------------- + // Text resources. + /// Retrieve resource as String based on assembly and partial resource name. public static String GetManifestResourceAsText(Assembly assembly, String partialPath, String resourceNameEndsWith) { - String fn = typeof(SacsResourceHelper).Name + ".GetManifestResourceAsText"; - if (StringUtil.IsEmpty(resourceNameEndsWith)) return ""; + if (StringUtil.IsBlank(resourceNameEndsWith)) return ""; using (Stream resourceStream = GetManifestResourceStream(assembly, partialPath, resourceNameEndsWith)) { @@ -195,12 +198,13 @@ namespace Sarand.Net.Standard.Base.Helpers } //------------------------------------------------------------------- + // Binary resources. + /// Retrieve resource as byte array based on assembly and partial resource name. public static byte[] GetManifestResourceAsBinary(Assembly assembly, String partialPath, String resourceNameEndsWith) { - String fn = typeof(SacsResourceHelper).Name + ".GetManifestResourceAsBinary"; if ( - StringUtil.IsEmpty(resourceNameEndsWith)) return null; + StringUtil.IsBlank(resourceNameEndsWith)) return null; using (Stream resourceStream = GetManifestResourceStream(assembly, partialPath, resourceNameEndsWith)) { if (resourceStream != null) @@ -211,29 +215,36 @@ namespace Sarand.Net.Standard.Base.Helpers } } } - SaLogger.Warn(fn + " Failed to locate text resource: " + resourceNameEndsWith); + SaLogger.Warn(SysUtil.Fn + " Failed to locate text resource: " + resourceNameEndsWith); return null; } //------------------------------------------------------------------- + // Resource stream. + + /// Retrieve resource as stream based on assembly and partial resource name. + public static Stream GetResourceStream(String partialPath, String resourceNameEndsWith) + { + return GetManifestResourceStream(MyAssembly, partialPath, resourceNameEndsWith); + } + /// Retrieve resource as stream based on assembly and partial resource name. public static Stream GetManifestResourceStream(Assembly assembly, String partialPath, String resourceNameEndsWith) { - String fn = typeof(SacsResourceHelper).Name + ".GetManifestResourceStream"; - //Logger.Debug(fn + " Manifest resource names: " + new List(assembly.GetManifestResourceNames()).Concat("","\n\t")); + //Logger.Debug(SysUtil.Fn + " Manifest resource names: " + new List(assembly.GetManifestResourceNames()).Concat("","\n\t")); foreach (String resourceName in assembly.GetManifestResourceNames()) { - //SaLogger.Debug(fn + " Resource: " + resourceName); + //SaLogger.Debug(SysUtil.Fn + " Resource: " + resourceName); // Match the partial path. - if (!StringUtil.IsEmpty(partialPath) && !resourceName.ContainsCI(partialPath)) continue; + if (!StringUtil.IsBlank(partialPath) && !resourceName.ContainsCI(partialPath)) continue; // Match the resource filename to the end of the resource name - resource names start with default namespace (eg. 'Sarand'). if (!resourceName.EndsWithCI(resourceNameEndsWith)) continue; - //SaLogger.Debug(fn + " Resource filename: " + resourceNameEndsWith + ". Matched to resource: " + resourceName); + //SaLogger.Debug(SysUtil.Fn + " Resource filename: " + resourceNameEndsWith + ". Matched to resource: " + resourceName); return assembly.GetManifestResourceStream(resourceName); } - SaLogger.Warn(fn + " Resource filename not found: " + resourceNameEndsWith); + SaLogger.Warn(SysUtil.Fn + " Resource filename not found: " + resourceNameEndsWith); return null; } diff --git a/SacsStandardBase/Base/IO/DirectoryUtil.cs b/SacsStandardBase/Base/IO/DirectoryUtil.cs index 1499543..3bb3952 100644 --- a/SacsStandardBase/Base/IO/DirectoryUtil.cs +++ b/SacsStandardBase/Base/IO/DirectoryUtil.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Text.RegularExpressions; using Sarand.Net.Standard.Base.App; using Sarand.Net.Standard.Base.Core; @@ -140,6 +141,14 @@ namespace Sarand.Net.Standard.Base.IO return null; } + //------------------------------------------------------------------- + // Utilities. + + public static String TrimTrailingSlashes (String path) + { + return Regex.Replace(path, "[\\\\/]+$", ""); + } + //------------------------------------------------------------------- } //======================================================================= diff --git a/SacsStandardBase/Base/Utils/AssemblyUtil.cs b/SacsStandardBase/Base/Utils/AssemblyUtil.cs index 64b60e2..67e44ee 100644 --- a/SacsStandardBase/Base/Utils/AssemblyUtil.cs +++ b/SacsStandardBase/Base/Utils/AssemblyUtil.cs @@ -14,7 +14,6 @@ namespace Sarand.Net.Standard.Base.Utils #region Gets the build date and time (by reading the COFF header) // http://msdn.microsoft.com/en-us/library/ms680313 - /* struct _IMAGE_FILE_HEADER { public ushort Machine; @@ -25,11 +24,9 @@ namespace Sarand.Net.Standard.Base.Utils public ushort SizeOfOptionalHeader; public ushort Characteristics; }; - */ - static DateTime GetBuildDateTime (Assembly assembly) + public static DateTime GetBuildDateTime (this Assembly assembly) { - /* // Not available until .Net Standard 1.5. var path = assembly.GetName().CodeBase; if (File.Exists(path)) @@ -47,15 +44,15 @@ namespace Sarand.Net.Standard.Base.Utils try { var coffHeader = (_IMAGE_FILE_HEADER)Marshal.PtrToStructure(pinnedBuffer.AddrOfPinnedObject(), typeof(_IMAGE_FILE_HEADER)); - - return TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1) + new TimeSpan(coffHeader.TimeDateStamp * TimeSpan.TicksPerSecond)); + DateTime buildDate = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + return buildDate.AddSeconds(coffHeader.TimeDateStamp); + //return TimeZoneInfo.Local.ToLocalTime(new DateTime(1970, 1, 1) + new TimeSpan(coffHeader.TimeDateStamp * TimeSpan.TicksPerSecond)); } finally { pinnedBuffer.Free(); } } - */ return new DateTime(); } #endregion diff --git a/SacsStandardBase/Base/Utils/StringUtil.cs b/SacsStandardBase/Base/Utils/StringUtil.cs index a780247..ba15816 100644 --- a/SacsStandardBase/Base/Utils/StringUtil.cs +++ b/SacsStandardBase/Base/Utils/StringUtil.cs @@ -381,7 +381,7 @@ namespace Sarand.Net.Standard.Base.Utils } /// - /// Concatenate the partial path values with the specified dlimiter, stripping leading and trailing slashes and delimiters, and converting slashes and delimiters to the required delimiter. + /// Concatenate the partial path values with the specified delimiter, stripping leading and trailing slashes and delimiters, and converting slashes and delimiters to the required delimiter. /// private static String CombineFilePath(char delim, params String[] values) { diff --git a/SacsStandardBase/SacsStandardBase.csproj b/SacsStandardBase/SacsStandardBase.csproj index 4bc5e37..1b41118 100644 --- a/SacsStandardBase/SacsStandardBase.csproj +++ b/SacsStandardBase/SacsStandardBase.csproj @@ -7,11 +7,11 @@ - + - +