Saxonite 1.2.11.3. Sandtrap.

This commit is contained in:
Andy Howard
2024-04-24 17:18:05 +01:00
parent 496aaeee0b
commit 7748941680
104 changed files with 5615 additions and 177 deletions
+12 -6
View File
@@ -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
@@ -19,7 +19,6 @@
<ProjectReference Include="..\SacsStandardAccounts\SacsStandardAccounts.csproj" />
<ProjectReference Include="..\SacsStandardBase\SacsStandardBase.csproj" />
<ProjectReference Include="..\SacsStandardDbas\SacsStandardDbas.csproj" />
<ProjectReference Include="..\SacsStandardMob\SacsStandardMob.csproj" />
</ItemGroup>
<ItemGroup>
@@ -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, " "));
}
//-------------------------------------------------------------------
}
}
+6 -9
View File
@@ -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;
/// <summary>
@@ -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;
}
+208
View File
@@ -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);
}
}
}
//-------------------------------------------------------------------
}
//=======================================================================
}
+60
View File
@@ -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);
//-------------------------------------------------------------------
}
//=======================================================================
}
+54
View File
@@ -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()
{
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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.
//------------------------------------------------------------------
}
//======================================================================
}
@@ -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
//-------------------------------------------------------------------
/// <summary>Control configuration that can be changed dynamically.</summary>
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<CheckedChangedEventArgs>? 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);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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.
/// <summary>The control itself. NB May be composite</summary>
protected abstract View ControlView { get; }
/// <summary>Control used for read-only display.</summary>
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
//-------------------------------------------------------------------
/// <summary>Control configuration that can be changed dynamically.</summary>
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<FocusEventArgs>? Focused;
protected void Control_Focused(object? sender, FocusEventArgs e)
{
if (Focused != null) Focused.Invoke(sender, e);
}
//-------------------------------------------------------------------
public new event EventHandler<FocusEventArgs>? 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;
}
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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
//-------------------------------------------------------------------
/// <summary>Control configuration that can be changed dynamically.</summary>
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<TextChangedEventArgs>? 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);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
+36
View File
@@ -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
//-------------------------------------------------------------------
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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.
//-------------------------------------------------------------------
}
//======================================================================
}
@@ -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<DateChangedEventArgs>? 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;
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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; }
}
/// <summary>Amount of space between date and time pickers.</summary>
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<DateChangedEventArgs>? DateSelected;
//-------------------------------------------------------------------
private void PickerTime_TimeChanged(object? sender, SamTimePicker.TimeChangedEventArgs e)
{
if (TimeChanged != null) TimeChanged.Invoke(sender, e);
}
public event EventHandler<SamTimePicker.TimeChangedEventArgs>? TimeChanged;
//-------------------------------------------------------------------
}
//=======================================================================
}
+84
View File
@@ -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();
}
//-------------------------------------------------------------------
}
//=======================================================================
}
+167
View File
@@ -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;
}
}
/// <summary>
/// Whether to format text as it is entered.
/// <para>NB This can lead to problems with the cursor position and typing doesn't give expected results.</para>
/// <para>Default: False.</para>
/// </summary>
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);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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.");
}
//-------------------------------------------------------------------
}
//=======================================================================
}
+78
View File
@@ -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.
/// <summary>Default (initial) font size.</summary>
public double FontSizeDefault { get; private set; }
public new double FontSize
{
get { return fontSize; }
set { fontSize = value; base.FontSize = fontSize * fontSizeProportion; }
}
/// <summary>Font size proportion.</summary>
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;
}
}
//-------------------------------------------------------------------
}
//=======================================================================
}
+178
View File
@@ -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<SamPickerItem> pickerItems = new List<SamPickerItem>();
//-------------------------------------------------------------------
// 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
//-------------------------------------------------------------------
/// <summary>
/// Does the list contain an item with the same Id.
/// <para>NB Invalid Id values are matched.</para>
/// </summary>
public bool ContainsItemId(SysId id)
{
return pickerItems.Exists(item => SysId.ToInt(item.Id) == SysId.ToInt(id));
}
/// <summary>
/// Does the list contain an item with the same code.
/// <para>NB Codes are case-insensitive.</para>
/// </summary>
public bool ContainsItemCode(String code)
{
return pickerItems.Exists(item => item.Code.EqualsCI(code));
}
//-------------------------------------------------------------------
/// <summary>Remove all items from the picker.</summary>
public void ClearItems()
{
Items.Clear();
ItemsSource = null;
pickerItems.Clear();
}
/// <summary>Replace existing picker item list.</summary>
public void SetItems(List<SamPickerItem> pickerItems)
{
ClearItems();
this.pickerItems.AddRange(pickerItems);
RefreshPickerItems();
}
//-------------------------------------------------------------------
/// <summary>
/// Add an item identified by a SysId value.
/// <para>NB Fails if an item already exists with the same id.</para>
/// </summary>
public bool AddItem(SysId id, String caption)
{
if (ContainsItemId(id)) return false;
pickerItems.Add(new SamPickerItem() { Id = id, Caption = caption });
RefreshPickerItems();
return ContainsItemId(id);
}
/// <summary>
/// Add an item identified by a code value.
/// <para>NB Fails if an item already exists with the same case-insensitive code.</para>
/// </summary>
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);
/// <summary>Picker population completed event handler.</summary>
public event PopulatedEventHandler? Populated;
protected void InvokePopulatedEvent()
{
if (Populated != null) Populated.Invoke(this, new PopulatedEventArgs() { });
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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<SamTabPanel> tabPanels = new List<SamTabPanel>();
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<SamTabPanel>() { tabPanel });
}
public void AddPanels(IEnumerable<SamTabPanel> 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
//-------------------------------------------------------------------
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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<TimeChangedEventArgs>? 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);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
+103
View File
@@ -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;
}
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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.
//--------------------------------------------------------------------
/// <summary>
/// Remove borders around entry and picker controls.
/// <para>Also make background transparent.</para>
/// </summary>
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
}
});
//---------------------------------------------------------------
}
//--------------------------------------------------------------------
}
//========================================================================
}
@@ -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.
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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.
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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);
}
//-------------------------------------------------------------------
@@ -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.
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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
{
//=======================================================================
/// <summary>
/// Wrapping columnar layout - to achieve resposive behaviour.
/// <para>Layout which performs wrapping on the boundaries.</para>
/// <para>Base Code -> https://forums.xamarin.com/discussion/comment/57486/#Comment_57486</para>
/// <para> http://bit.ly/xf-custompanel</para>
/// </summary>
//=======================================================================
public class SamWrapLayout : Layout<View>
{
//-------------------------------------------------------------------
/// <summary>Horizontal spacing between elements.</summary>
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()
);
/// <summary>Vertical spacing between elements.</summary>
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()
);
//-------------------------------------------------------------------
/// <summary>Number of uniform columns in each row.</summary>
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()
);
//-------------------------------------------------------------------
/// <summary>Item height equals item width when UniformColums > 0</summary>
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));
}
//-------------------------------------------------------------------
}
//=======================================================================
}
+182
View File
@@ -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<bool> 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();
}
//-------------------------------------------------------------------
}
//=======================================================================
}
+81
View File
@@ -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);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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<SacsFilterPropertyType> FilterPropertyTypes { get; } = new List<SacsFilterPropertyType>();
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<int> selectedPropertyTypes = new List<int>();
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<SacsFilterPropertyType> filterPropertyTypes = new List<SacsFilterPropertyType>(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<FilterChangedEventArgs>? 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);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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<SacsFilterPropertyType> FilterPropertyTypes { get; } = new List<SacsFilterPropertyType>();
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<PropertyFilterChangedEventArgs>? 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);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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<SacsFilterPropertyType> FilterPropertyTypes { get; } = new List<SacsFilterPropertyType>();
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<PagingActionEventArgs>? 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
//-------------------------------------------------------------------
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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
{
//=======================================================================
/// <summary>
/// Panel to display with item list where no filter required, eg. items associated with parent.
/// <para>- Message shown to left</para>
/// <para>- Buttons shown to right</para>
/// </summary>
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<EventArgs>? AddClicked;
protected virtual void ButtonAddItem_Clicked(object? sender, EventArgs e)
{
if (AddClicked != null) AddClicked.Invoke(sender, e);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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<SacsMessage> messages = new List<SacsMessage>();
// 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
//-------------------------------------------------------------------
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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;
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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;
}
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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
//-------------------------------------------------------------------
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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<PropertyData> properties = new List<PropertyData>();
// 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
//-------------------------------------------------------------------
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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; }
}
/// <summary>
/// Tab Caption panel
/// </summary>
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<TabPanelData> tabPanels = new List<TabPanelData>();
//-------------------------------------------------------------------
// 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);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
+52
View File
@@ -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
//-------------------------------------------------------------------
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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
{
//-------------------------------------------------------------------
/// <summary>
/// Identify the page fo rthis element.
/// </summary>
public static Page? GetPage(this Element element)
{
while (element != null)
{
if (element is Page) return element as Page;
element = element.Parent;
}
return null;
}
//-------------------------------------------------------------------
}
//=======================================================================
}
+49
View File
@@ -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<bool>();
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;
}
//-------------------------------------------------------------------
}
//=======================================================================
}
+25
View File
@@ -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
{
//-------------------------------------------------------------------
/// <summary>
/// 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.
/// </summary>
public static ImageSource GetImageFromByteArray(byte[] imageAsBytes)
{
return ImageSource.FromStream(() => new MemoryStream(imageAsBytes));
}
//-------------------------------------------------------------------
}
//=======================================================================
}
+18
View File
@@ -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
{
//-------------------------------------------------------------------
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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()}");
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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.
//-------------------------------------------------------------------
/// <summary>Is the current thread the main thread.</summary>
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
//-------------------------------------------------------------------
/// <summary>Invoke task on main thread.</summary>
public static void InvokeOnMainThread(Action taskFn)
{
MainThread.BeginInvokeOnMainThread(() =>
{
taskFn();
});
}
/// <summary>Invoke task on main thread and wait for completion.</summary>
public static void InvokeOnMainThreadSync(Action taskFn)
{
var tcs = new TaskCompletionSource<Object>();
MainThread.BeginInvokeOnMainThread(() =>
{
try
{
taskFn();
tcs.SetResult(true);
}
catch (Exception ex) { tcs.SetException(ex); }
});
}
/// <summary>Invoke task on main thread and wait for completion.</summary>
public static T InvokeOnMainThreadSync<T>(Func<T> taskFn)
{
var tcs = new TaskCompletionSource<T>();
MainThread.BeginInvokeOnMainThread(() =>
{
try
{
var result = taskFn();
tcs.SetResult(result);
}
catch (Exception ex) { tcs.SetException(ex); }
});
return tcs.Task.Result;
}
//-------------------------------------------------------------------
}
//=======================================================================
}
+28
View File
@@ -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;
}
}
//=======================================================================
}
+28
View File
@@ -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
{
//-------------------------------------------------------------------
/// <summary>
/// Configure layout of components when visual properties (eg. change in orientation) occurs.
/// <para>Automatically called by parent page when dimensions change.</para>
/// <para>NB Not to be used for initial population of components as this method may be called multiple times.</para>
/// </summary>
void ConfigureComponents();
void SetControlActivity();
void SetControlsReadOnly();
//-------------------------------------------------------------------
}
//======================================================================
}
+46
View File
@@ -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()
{
}
//-------------------------------------------------------------------
}
//=======================================================================
}
+46
View File
@@ -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()
{
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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();
}
}
//-------------------------------------------------------------------
}
//=======================================================================
}
+46
View File
@@ -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()
{
}
//-------------------------------------------------------------------
}
//=======================================================================
}
+46
View File
@@ -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()
{
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,7 @@
namespace SacsMobileMaui
{
// All the code in this file is only included on Android.
public class PlatformClass1
{
}
}
@@ -0,0 +1,7 @@
namespace SacsMobileMaui
{
// All the code in this file is only included on Mac Catalyst.
public class PlatformClass1
{
}
}
@@ -0,0 +1,9 @@
using System;
namespace SacsMobileMaui
{
// All the code in this file is only included on Tizen.
public class PlatformClass1
{
}
}
@@ -0,0 +1,7 @@
namespace SacsMobileMaui
{
// All the code in this file is only included on Windows.
public class PlatformClass1
{
}
}
@@ -0,0 +1,7 @@
namespace SacsMobileMaui
{
// All the code in this file is only included on iOS.
public class PlatformClass1
{
}
}
+32
View File
@@ -0,0 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks>
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
<!-- <TargetFrameworks>$(TargetFrameworks);net8.0-tizen</TargetFrameworks> -->
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.4</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">13.1</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.3</SupportedOSPlatformVersion>
<RootNamespace>Sarand.Net.Mobile</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Maui.Controls" Version="8.0.20" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="8.0.20" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SacsStandardBase\SacsStandardBase.csproj" />
</ItemGroup>
</Project>
@@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>Sarand.Net.Standard</RootNamespace>
<RootNamespace>Sarand.Net.Mobile</RootNamespace>
</PropertyGroup>
<ItemGroup>
@@ -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;
@@ -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
@@ -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
@@ -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
@@ -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();
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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<SlmPickerItem> pickerItems = new List<SlmPickerItem>();
private readonly List<SaxPickerItem> pickerItems = new List<SaxPickerItem>();
//-------------------------------------------------------------------
// Construction.
@@ -69,7 +69,7 @@ namespace Sarand.Net.Standard.Mobile.Forms.Controls
pickerItems.Clear();
}
/// <summary>Replace existing picker item list.</summary>
public void SetItems (List<SlmPickerItem> pickerItems)
public void SetItems (List<SaxPickerItem> 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -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
@@ -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
{
//=======================================================================
/// <summary>
@@ -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
@@ -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
@@ -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
@@ -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.
@@ -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<PagingActionEventArgs> 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);
}
@@ -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
{
//=======================================================================
/// <summary>
@@ -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);
}
@@ -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<SacsMessage> messages = new List<SacsMessage>();
// Components.
private SaxStackLayout mainLayout = new SaxStackLayout() { Orientation = Xamarin.Forms.StackOrientation.Vertical };
private SaxStackLayout mainLayout = new SaxStackLayout() { Orientation = StackOrientation.Vertical };
//-------------------------------------------------------------------
// Construction.
@@ -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.
@@ -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.
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
// </ItemGroup>
// 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.
/// <summary>Retrieve resource as String based on assembly and partial resource name.</summary>
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.
/// <summary>Retrieve resource as byte array based on assembly and partial resource name.</summary>
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.
/// <summary>Retrieve resource as stream based on assembly and partial resource name.</summary>
public static Stream GetResourceStream(String partialPath, String resourceNameEndsWith)
{
return GetManifestResourceStream(MyAssembly, partialPath, resourceNameEndsWith);
}
/// <summary>Retrieve resource as stream based on assembly and partial resource name.</summary>
public static Stream GetManifestResourceStream(Assembly assembly, String partialPath, String resourceNameEndsWith)
{
String fn = typeof(SacsResourceHelper).Name + ".GetManifestResourceStream";
//Logger.Debug(fn + " Manifest resource names: " + new List<String>(assembly.GetManifestResourceNames()).Concat("","\n\t"));
//Logger.Debug(SysUtil.Fn + " Manifest resource names: " + new List<String>(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;
}

Some files were not shown because too many files have changed in this diff Show More