mirror of
https://dev.azure.com/TeilRad/sharee.bike%20App/_git/Code
synced 2025-06-21 13:36:28 +02:00
Version 3.0.381
This commit is contained in:
parent
f963c0a219
commit
3a363acf3a
1525 changed files with 60589 additions and 125098 deletions
19
SharedBusinessLogic/View/BoolInverterConverter.cs
Normal file
19
SharedBusinessLogic/View/BoolInverterConverter.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace ShareeBike.View
|
||||
{
|
||||
/// <summary> Inverts a bool.</summary>
|
||||
public class BoolInverterConverter : IValueConverter
|
||||
{
|
||||
/// <summary> Inverts a bool.</summary>
|
||||
/// <param name="value">Bool to invert.</param>
|
||||
/// <returns>Inverted bool.</returns>
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
=> value is bool flag && !flag;
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
=> value is bool flag && !flag;
|
||||
}
|
||||
}
|
126
SharedBusinessLogic/View/IViewService.cs
Normal file
126
SharedBusinessLogic/View/IViewService.cs
Normal file
|
@ -0,0 +1,126 @@
|
|||
using System.Threading.Tasks;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
|
||||
|
||||
namespace ShareeBike.View
|
||||
{
|
||||
public interface IViewService
|
||||
{
|
||||
/// <summary> Displays alert message. </summary>
|
||||
/// <param name="title">Title of message.</param>
|
||||
/// <param name="message">Message to display.</param>
|
||||
/// <param name="cancel">Text of button.</param>
|
||||
Task DisplayAlert(
|
||||
string title,
|
||||
string message,
|
||||
string cancel);
|
||||
|
||||
/// <summary> Displays alert message. </summary>
|
||||
/// <param name="title">Title of message.</param>
|
||||
/// <param name="message">Message to display.</param>
|
||||
/// <param name="details">Detailed error description.</param>
|
||||
/// <param name="cancel">Text of button.</param>
|
||||
Task DisplayAdvancedAlert(
|
||||
string title,
|
||||
string message,
|
||||
string details,
|
||||
string cancel);
|
||||
|
||||
/// <summary> Displays alert message. </summary>
|
||||
/// <param name="title">Title of message.</param>
|
||||
/// <param name="message">Message to display.</param>
|
||||
/// <param name="accept">Text of accept button.</param>
|
||||
/// <param name="cancel">Text of button.</param>
|
||||
/// <returns>True if user pressed accept.</returns>
|
||||
Task<bool> DisplayAlert(string title, string message, string accept, string cancel);
|
||||
|
||||
/// <summary> Displays alert message. </summary>
|
||||
/// <param name="title">Title of message.</param>
|
||||
/// <param name="message">Message to display.</param>
|
||||
/// <param name="details">Detailed error description.</param>
|
||||
/// <param name="accept">Text of accept button.</param>
|
||||
/// <param name="cancel">Text of button.</param>
|
||||
/// <returns>True if user pressed accept.</returns>
|
||||
Task<bool> DisplayAdvancedAlert(string title, string message, string details, string accept, string cancel);
|
||||
|
||||
/// <summary> Displays an action sheet. </summary>
|
||||
/// <param name="title">Title of message.</param>
|
||||
/// <param name="message">Message to display.</param>
|
||||
/// <param name="cancel">Text of button.</param>
|
||||
/// <param name="destruction"></param>
|
||||
/// <param name="buttons">Buttons holding options to select.</param>
|
||||
/// <returns>T</returns>
|
||||
Task<string> DisplayActionSheet(string title, string cancel, string destruction, params string[] buttons);
|
||||
|
||||
/// <summary> Shows a page.</summary>
|
||||
/// <param name="route">Route of the page to show.</param>
|
||||
#if USCSHARP9
|
||||
public Task ShowPage(string route);
|
||||
#else
|
||||
Task ShowPage(string route);
|
||||
#endif
|
||||
|
||||
/// <summary> Pushes a page onto the stack. </summary>
|
||||
/// <param name="typeOfPage">Page to display.</param>
|
||||
Task PushAsync(ViewTypes typeOfPage);
|
||||
|
||||
/// <summary> Pushes a page onto the modal stack. </summary>
|
||||
/// <param name="typeOfPage">Page to display.</param>
|
||||
Task PushModalAsync(ViewTypes typeOfPage);
|
||||
|
||||
/// <summary> Pushes a page onto the modal stack. </summary>
|
||||
Task PopModalAsync();
|
||||
|
||||
/// <summary> Displays user feedback popup.</summary>
|
||||
/// <param name="battery">Object holding info about battery. For some batteries charging level might need to be updated by user.</param>
|
||||
/// <returns>User feedback.</returns>
|
||||
Task<IUserFeedback> DisplayUserFeedbackPopup(
|
||||
IBatteryMutable battery = null);
|
||||
|
||||
#if USCSHARP9
|
||||
/// <summary>
|
||||
/// Feedback given by user when returning bike.
|
||||
/// </summary>
|
||||
public interface IUserFeedback
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds whether bike is broken or not.
|
||||
/// </summary>
|
||||
bool IsBikeBroken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds either
|
||||
/// - general feedback
|
||||
/// - error description of broken bike
|
||||
/// or both.
|
||||
/// </summary>
|
||||
string Message { get; set; }
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !USCSHARP9
|
||||
/// <summary>
|
||||
/// Feedback given by user when returning bike.
|
||||
/// </summary>
|
||||
public interface IUserFeedback
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds the current charging level of the battery in bars, null if unknown.
|
||||
/// </summary>
|
||||
int? CurrentChargeBars { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds whether bike is broken or not.
|
||||
/// </summary>
|
||||
bool IsBikeBroken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds either
|
||||
/// - general feedback
|
||||
/// - error description of broken bike
|
||||
/// or both.
|
||||
/// </summary>
|
||||
string Message { get; set; }
|
||||
}
|
||||
#endif
|
||||
}
|
35
SharedBusinessLogic/View/ListViewAttachedBehavior.cs
Normal file
35
SharedBusinessLogic/View/ListViewAttachedBehavior.cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
using System.Windows.Input;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace ShareeBike.View
|
||||
{
|
||||
public static class ListViewAttachedBehavior
|
||||
{
|
||||
public static readonly BindableProperty CommandProperty =
|
||||
BindableProperty.CreateAttached(
|
||||
"Command",
|
||||
typeof(ICommand),
|
||||
typeof(ListViewAttachedBehavior),
|
||||
null,
|
||||
propertyChanged: OnCommandChanged);
|
||||
|
||||
static void OnCommandChanged(BindableObject view, object oldValue, object newValue)
|
||||
{
|
||||
var entry = view as ListView;
|
||||
if (entry == null)
|
||||
return;
|
||||
|
||||
entry.ItemTapped += (sender, e) =>
|
||||
{
|
||||
var command = (newValue as ICommand);
|
||||
if (command == null)
|
||||
return;
|
||||
|
||||
if (command.CanExecute(e.Item))
|
||||
{
|
||||
command.Execute(e.Item);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using ShareeBike.Model.User.Account;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace ShareeBike.View.Settings
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Translates user permissions into visibility state.
|
||||
/// Used for container which holds a bunch of GUI elemets which migth all/ partly/ none be visible
|
||||
/// If all childs are invisible frame must be invisible as well. As soon as one child is visible frame must be visible as well.
|
||||
/// </summary>
|
||||
public class BackendPermissionsToVisibleConverter : IValueConverter
|
||||
{
|
||||
/// <summary> Converts permission value into visible state.</summary>
|
||||
/// <param name="value">Permission value from view model used to derive whether object is visible or not.</param>
|
||||
/// <returns>Boolean value indicating whether object is visible or not.</returns>
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
var enumValue = (Permissions)value;
|
||||
return enumValue.HasFlag(Permissions.PickCopriServer) | enumValue.HasFlag(Permissions.ManagePolling) | enumValue.HasFlag(Permissions.ManageCopriCacheExpiration);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return Permissions.None;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using ShareeBike.Model.User.Account;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace ShareeBike.View.Settings
|
||||
{
|
||||
/// <summary> Translates user permissions into visibility state. </summary>
|
||||
public class PermissionToVisibleConverter : BindableObject, IValueConverter
|
||||
{
|
||||
static readonly BindableProperty VisibleFlagProperty =
|
||||
BindableProperty.Create(nameof(VisibleFlag), typeof(Permissions), typeof(BindableObject));
|
||||
|
||||
/// <summary> Property set from XAML determinig for which permission value object is visible.</summary>
|
||||
public Permissions VisibleFlag
|
||||
{
|
||||
get => (Permissions)GetValue(VisibleFlagProperty);
|
||||
set => SetValue(VisibleFlagProperty, value);
|
||||
}
|
||||
|
||||
/// <summary> Converts permission value into visible state.</summary>
|
||||
/// <param name="value">Permission value from view model used to derive whether object is visible or not.</param>
|
||||
/// <returns>Boolean value indicating whether object is visible or not.</returns>
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return ((Permissions)value).HasFlag(VisibleFlag);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return Permissions.None;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace ShareeBike.View
|
||||
{
|
||||
/// <summary> Converts a string into visible state. If string is null or empty element becomes invisible.</summary>
|
||||
public class StringNotNullOrEmptyToVisibleConverter : IValueConverter
|
||||
{
|
||||
/// <summary> Converts a string into visible state.</summary>
|
||||
/// <param name="value">Text value from view model used to derive whether object is visible or not.</param>
|
||||
/// <returns>Boolean value indicating whether object is visible or not.</returns>
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return value != null && value is string text && !string.IsNullOrEmpty(text);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
7
SharedBusinessLogic/View/Themes/ITheme.cs
Normal file
7
SharedBusinessLogic/View/Themes/ITheme.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace ShareeBike.View.Themes
|
||||
{
|
||||
public interface ITheme
|
||||
{
|
||||
string OperatorInfo { get; }
|
||||
}
|
||||
}
|
196
SharedBusinessLogic/View/Themes/LastenradBayern.xaml
Normal file
196
SharedBusinessLogic/View/Themes/LastenradBayern.xaml
Normal file
|
@ -0,0 +1,196 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ResourceDictionary
|
||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
|
||||
x:Class="ShareeBike.Themes.LastenradBayern">
|
||||
|
||||
<!--Main color-->
|
||||
<Color x:Key="primary-back-title-color">#009BDB</Color>
|
||||
<Color x:Key="bright-primary-back-title-color">#C5E6E6</Color>
|
||||
|
||||
<!--Background color-->
|
||||
<Color x:Key="background-color">#BEBEBE</Color>
|
||||
|
||||
<!--Important text color-->
|
||||
<Color x:Key="important-text-color">#ff0000</Color>
|
||||
|
||||
<!--Attention color-->
|
||||
<Color x:Key="attention-color">#FF9214</Color>
|
||||
|
||||
<!--RentalProcess colors-->
|
||||
<Color x:Key="process-step-upcoming">#999999</Color>
|
||||
<Color x:Key="process-step-active">#0D0D0D</Color>
|
||||
<Color x:Key="process-step-succeeded">#00813e</Color>
|
||||
<Color x:Key="process-step-failed">#ff0000</Color>
|
||||
|
||||
<!--Primary Button-->
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="WidthRequest" Value="400" />
|
||||
<Setter Property="HorizontalOptions" Value="Center" />
|
||||
<Setter Property="BorderWidth" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="0" />
|
||||
<Setter Property="FontSize" Value="Medium"/>
|
||||
<Setter Property="FontFamily" Value="RobotoRegular"/>
|
||||
<Setter Property="BorderColor" Value="{DynamicResource Key=primary-back-title-color}"/>
|
||||
<Setter Property="BackgroundColor" Value="{DynamicResource Key=primary-back-title-color}"/>
|
||||
<Setter Property="TextColor" Value="White"/>
|
||||
<Style.Triggers>
|
||||
<Trigger TargetType="Button"
|
||||
Property="IsEnabled"
|
||||
Value="False">
|
||||
<Setter Property="BorderColor" Value="DimGray"/>
|
||||
<Setter Property="BackgroundColor" Value="DimGray"/>
|
||||
<Setter Property="TextColor" Value="LightGray"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!--Secondary Button-->
|
||||
<Style x:Key="SecondaryButton" TargetType="Button">
|
||||
<Setter Property="WidthRequest" Value="400" />
|
||||
<Setter Property="HorizontalOptions" Value="Center" />
|
||||
<Setter Property="BorderWidth" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="0" />
|
||||
<Setter Property="FontSize" Value="Medium"/>
|
||||
<Setter Property="FontFamily" Value="RobotoRegular"/>
|
||||
<Setter Property="BorderColor" Value="{DynamicResource Key=primary-back-title-color}"/>
|
||||
<Setter Property="BackgroundColor" Value="White"/>
|
||||
<Setter Property="TextColor" Value="{DynamicResource Key=primary-back-title-color}"/>
|
||||
<Style.Triggers>
|
||||
<Trigger TargetType="Button"
|
||||
Property="IsEnabled"
|
||||
Value="False">
|
||||
<Setter Property="BorderColor" Value="DimGray"/>
|
||||
<Setter Property="BackgroundColor" Value="LightGray"/>
|
||||
<Setter Property="TextColor" Value="DimGray"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!--Button without outline-->
|
||||
<Style x:Key="NoOutlineButtonWhite" TargetType="Button">
|
||||
<Setter Property="WidthRequest" Value="400" />
|
||||
<Setter Property="HorizontalOptions" Value="Center" />
|
||||
<Setter Property="BorderWidth" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="0" />
|
||||
<Setter Property="FontSize" Value="Medium"/>
|
||||
<Setter Property="FontFamily" Value="RobotoRegular"/>
|
||||
<Setter Property="BorderColor" Value="White"/>
|
||||
<Setter Property="BackgroundColor" Value="White"/>
|
||||
<Setter Property="TextColor" Value="{DynamicResource Key=primary-back-title-color}"/>
|
||||
<Style.Triggers>
|
||||
<Trigger TargetType="Button"
|
||||
Property="IsEnabled"
|
||||
Value="False">
|
||||
<Setter Property="TextColor" Value="DimGray"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="NoOutlineButtonBackgroundColor" TargetType="Button">
|
||||
<Setter Property="WidthRequest" Value="400" />
|
||||
<Setter Property="HorizontalOptions" Value="Center" />
|
||||
<Setter Property="BorderWidth" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="0" />
|
||||
<Setter Property="FontSize" Value="Medium"/>
|
||||
<Setter Property="FontFamily" Value="RobotoRegular"/>
|
||||
<Setter Property="BorderColor" Value="{DynamicResource Key=background-color}"/>
|
||||
<Setter Property="BackgroundColor" Value="{DynamicResource Key=background-color}"/>
|
||||
<Setter Property="TextColor" Value="{DynamicResource Key=primary-back-title-color}"/>
|
||||
<Style.Triggers>
|
||||
<Trigger TargetType="Button"
|
||||
Property="IsEnabled"
|
||||
Value="False">
|
||||
<Setter Property="TextColor" Value="DimGray"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!--Frame-->
|
||||
<Style TargetType="Frame">
|
||||
<Setter Property="CornerRadius" Value="0" />
|
||||
<Setter Property="HasShadow" Value="False" />
|
||||
</Style>
|
||||
|
||||
<Style x:Key="RunningProcessFrame" TargetType="Frame">
|
||||
<Setter Property="CornerRadius" Value="0" />
|
||||
<Setter Property="HasShadow" Value="False" />
|
||||
</Style>
|
||||
|
||||
<!--Switch-->
|
||||
<Style TargetType="Switch">
|
||||
<Style.Triggers>
|
||||
<Trigger TargetType="Switch"
|
||||
Property="IsToggled"
|
||||
Value="True">
|
||||
<Setter Property="ThumbColor" Value="{DynamicResource Key=primary-back-title-color}"/>
|
||||
<Setter Property="OnColor" Value="{DynamicResource Key=bright-primary-back-title-color}"/>
|
||||
</Trigger>
|
||||
<Trigger TargetType="Switch"
|
||||
Property="IsToggled"
|
||||
Value="False">
|
||||
<Setter Property="ThumbColor" Value="DimGray"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!--Slider-->
|
||||
<Style TargetType="Slider">
|
||||
<Setter Property="ThumbColor" Value="{DynamicResource Key=primary-back-title-color}"/>
|
||||
</Style>
|
||||
|
||||
<!--Label-->
|
||||
<Style TargetType="Label">
|
||||
<Setter Property="FontSize" Value="Default"/>
|
||||
<Setter Property="FontFamily" Value="RobotoRegular"/>
|
||||
<Style.Triggers>
|
||||
<Trigger TargetType="Label"
|
||||
Property="FontAttributes"
|
||||
Value="Bold">
|
||||
<Setter Property="FontFamily" Value="RobotoBold"/>
|
||||
</Trigger>
|
||||
<Trigger TargetType="Label"
|
||||
Property="FontAttributes"
|
||||
Value="Italic">
|
||||
<Setter Property="FontFamily" Value="RobotoItalic"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!--Entry-->
|
||||
<Style TargetType="Entry">
|
||||
<Setter Property="FontSize" Value="Default"/>
|
||||
<Setter Property="FontFamily" Value="RobotoRegular"/>
|
||||
</Style>
|
||||
|
||||
<!--Flyout Item-->
|
||||
<Style TargetType="FlyoutItem">
|
||||
<Setter Property="Shell.BackgroundColor" Value="{DynamicResource Key=primary-back-title-color}" />
|
||||
</Style>
|
||||
|
||||
<!--Navbar-->
|
||||
<Style x:Key="Label-Navbar" TargetType="Label">
|
||||
<Setter Property="FontSize" Value="20"/>
|
||||
<Setter Property="FontFamily" Value="RobotoRegular"/>
|
||||
<Setter Property="TextColor" Value="White"/>
|
||||
<Setter Property="VerticalOptions" Value="Start"/>
|
||||
<Setter Property="HorizontalOptions" Value="Start"/>
|
||||
<Setter Property="Padding" Value="0,14,0,12"/>
|
||||
<Setter Property="MaxLines" Value="1"/>
|
||||
</Style>
|
||||
<Style x:Key="Image-Navbar" TargetType="Image">
|
||||
<Setter Property="Source" Value="navbar_theme.png"/>
|
||||
<Setter Property="Aspect" Value="AspectFill"/>
|
||||
<Setter Property="Grid.ColumnSpan" Value="2"/>
|
||||
</Style>
|
||||
|
||||
<!--TabbedPage-->
|
||||
<Style x:Key="TabbedPageStyle" TargetType="TabbedPage">
|
||||
<Setter Property="BarBackgroundColor" Value="White"/>
|
||||
<Setter Property="UnselectedTabColor" Value="DimGray"/>
|
||||
<Setter Property="SelectedTabColor" Value="{x:DynamicResource primary-back-title-color}"/>
|
||||
<Setter Property="android:TabbedPage.ToolbarPlacement" Value="Default"/>
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
19
SharedBusinessLogic/View/Themes/LastenradBayern.xaml.cs
Normal file
19
SharedBusinessLogic/View/Themes/LastenradBayern.xaml.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using ShareeBike.View.Themes;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace ShareeBike.Themes
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class LastenradBayern : ResourceDictionary, ITheme
|
||||
{
|
||||
public const string OPERATORINFO = "Lastenrad Bayern";
|
||||
|
||||
public LastenradBayern()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public string OperatorInfo => OPERATORINFO;
|
||||
}
|
||||
}
|
196
SharedBusinessLogic/View/Themes/ShareeBike.xaml
Normal file
196
SharedBusinessLogic/View/Themes/ShareeBike.xaml
Normal file
|
@ -0,0 +1,196 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ResourceDictionary
|
||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
|
||||
x:Class="ShareeBike.Themes.ShareeBike">
|
||||
|
||||
<!--Main color-->
|
||||
<Color x:Key="primary-back-title-color">#009899</Color>
|
||||
<Color x:Key="bright-primary-back-title-color">#B5E6E6</Color>
|
||||
|
||||
<!--Background color-->
|
||||
<Color x:Key="background-color">#BEBEBE</Color>
|
||||
|
||||
<!--Important text color-->
|
||||
<Color x:Key="important-text-color">#BF2828</Color>
|
||||
|
||||
<!--Attention color-->
|
||||
<Color x:Key="attention-color">#FC870D</Color>
|
||||
|
||||
<!--RentalProcess colors-->
|
||||
<Color x:Key="process-step-upcoming">#999999</Color>
|
||||
<Color x:Key="process-step-active">#0D0D0D</Color>
|
||||
<Color x:Key="process-step-succeeded">#5DBF3B</Color>
|
||||
<Color x:Key="process-step-failed">#BF2828</Color>
|
||||
|
||||
<!--Primary Button-->
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="WidthRequest" Value="400" />
|
||||
<Setter Property="HorizontalOptions" Value="Center" />
|
||||
<Setter Property="BorderWidth" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="10" />
|
||||
<Setter Property="FontSize" Value="Medium"/>
|
||||
<Setter Property="FontFamily" Value="RobotoRegular"/>
|
||||
<Setter Property="BorderColor" Value="{DynamicResource Key=primary-back-title-color}"/>
|
||||
<Setter Property="BackgroundColor" Value="{DynamicResource Key=primary-back-title-color}"/>
|
||||
<Setter Property="TextColor" Value="White"/>
|
||||
<Style.Triggers>
|
||||
<Trigger TargetType="Button"
|
||||
Property="IsEnabled"
|
||||
Value="False">
|
||||
<Setter Property="BorderColor" Value="DimGray"/>
|
||||
<Setter Property="BackgroundColor" Value="DimGray"/>
|
||||
<Setter Property="TextColor" Value="LightGray"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!--Secondary Button-->
|
||||
<Style x:Key="SecondaryButton" TargetType="Button">
|
||||
<Setter Property="WidthRequest" Value="400" />
|
||||
<Setter Property="HorizontalOptions" Value="Center" />
|
||||
<Setter Property="BorderWidth" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="10" />
|
||||
<Setter Property="FontSize" Value="Medium"/>
|
||||
<Setter Property="FontFamily" Value="RobotoRegular"/>
|
||||
<Setter Property="BorderColor" Value="{DynamicResource Key=primary-back-title-color}"/>
|
||||
<Setter Property="BackgroundColor" Value="White"/>
|
||||
<Setter Property="TextColor" Value="{DynamicResource Key=primary-back-title-color}"/>
|
||||
<Style.Triggers>
|
||||
<Trigger TargetType="Button"
|
||||
Property="IsEnabled"
|
||||
Value="False">
|
||||
<Setter Property="BorderColor" Value="DimGray"/>
|
||||
<Setter Property="BackgroundColor" Value="LightGray"/>
|
||||
<Setter Property="TextColor" Value="DimGray"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!--Button without outline-->
|
||||
<Style x:Key="NoOutlineButtonWhite" TargetType="Button">
|
||||
<Setter Property="WidthRequest" Value="400" />
|
||||
<Setter Property="HorizontalOptions" Value="Center" />
|
||||
<Setter Property="BorderWidth" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="10" />
|
||||
<Setter Property="FontSize" Value="Medium"/>
|
||||
<Setter Property="FontFamily" Value="RobotoRegular"/>
|
||||
<Setter Property="BorderColor" Value="White"/>
|
||||
<Setter Property="BackgroundColor" Value="White"/>
|
||||
<Setter Property="TextColor" Value="{DynamicResource Key=primary-back-title-color}"/>
|
||||
<Style.Triggers>
|
||||
<Trigger TargetType="Button"
|
||||
Property="IsEnabled"
|
||||
Value="False">
|
||||
<Setter Property="TextColor" Value="DimGray"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="NoOutlineButtonBackgroundColor" TargetType="Button">
|
||||
<Setter Property="WidthRequest" Value="400" />
|
||||
<Setter Property="HorizontalOptions" Value="Center" />
|
||||
<Setter Property="BorderWidth" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="10" />
|
||||
<Setter Property="FontSize" Value="Medium"/>
|
||||
<Setter Property="FontFamily" Value="RobotoRegular"/>
|
||||
<Setter Property="BorderColor" Value="{DynamicResource Key=background-color}"/>
|
||||
<Setter Property="BackgroundColor" Value="{DynamicResource Key=background-color}"/>
|
||||
<Setter Property="TextColor" Value="{DynamicResource Key=primary-back-title-color}"/>
|
||||
<Style.Triggers>
|
||||
<Trigger TargetType="Button"
|
||||
Property="IsEnabled"
|
||||
Value="False">
|
||||
<Setter Property="TextColor" Value="DimGray"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!--Frame-->
|
||||
<Style TargetType="Frame">
|
||||
<Setter Property="CornerRadius" Value="0" />
|
||||
<Setter Property="HasShadow" Value="False" />
|
||||
</Style>
|
||||
|
||||
<Style x:Key="RunningProcessFrame" TargetType="Frame">
|
||||
<Setter Property="CornerRadius" Value="10" />
|
||||
<Setter Property="HasShadow" Value="False" />
|
||||
</Style>
|
||||
|
||||
<!--Switch-->
|
||||
<Style TargetType="Switch">
|
||||
<Style.Triggers>
|
||||
<Trigger TargetType="Switch"
|
||||
Property="IsToggled"
|
||||
Value="True">
|
||||
<Setter Property="ThumbColor" Value="{DynamicResource Key=primary-back-title-color}"/>
|
||||
<Setter Property="OnColor" Value="{DynamicResource Key=bright-primary-back-title-color}"/>
|
||||
</Trigger>
|
||||
<Trigger TargetType="Switch"
|
||||
Property="IsToggled"
|
||||
Value="False">
|
||||
<Setter Property="ThumbColor" Value="DimGray"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!--Slider-->
|
||||
<Style TargetType="Slider">
|
||||
<Setter Property="ThumbColor" Value="{DynamicResource Key=primary-back-title-color}"/>
|
||||
</Style>
|
||||
|
||||
<!--Label-->
|
||||
<Style TargetType="Label">
|
||||
<Setter Property="FontSize" Value="Default"/>
|
||||
<Setter Property="FontFamily" Value="RobotoRegular"/>
|
||||
<Style.Triggers>
|
||||
<Trigger TargetType="Label"
|
||||
Property="FontAttributes"
|
||||
Value="Bold">
|
||||
<Setter Property="FontFamily" Value="RobotoBold"/>
|
||||
</Trigger>
|
||||
<Trigger TargetType="Label"
|
||||
Property="FontAttributes"
|
||||
Value="Italic">
|
||||
<Setter Property="FontFamily" Value="RobotoItalic"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!--Entry-->
|
||||
<Style TargetType="Entry">
|
||||
<Setter Property="FontSize" Value="Default"/>
|
||||
<Setter Property="FontFamily" Value="RobotoRegular"/>
|
||||
</Style>
|
||||
|
||||
<!--Flyout Item-->
|
||||
<Style TargetType="FlyoutItem">
|
||||
<Setter Property="Shell.BackgroundColor" Value="{DynamicResource Key=primary-back-title-color}" />
|
||||
</Style>
|
||||
|
||||
<!--Navbar-->
|
||||
<Style x:Key="Label-Navbar" TargetType="Label">
|
||||
<Setter Property="FontSize" Value="20"/>
|
||||
<Setter Property="FontFamily" Value="RobotoRegular"/>
|
||||
<Setter Property="TextColor" Value="White"/>
|
||||
<Setter Property="VerticalOptions" Value="Start"/>
|
||||
<Setter Property="HorizontalOptions" Value="Start"/>
|
||||
<Setter Property="Padding" Value="0,14,0,12"/>
|
||||
<Setter Property="MaxLines" Value="1"/>
|
||||
</Style>
|
||||
<Style x:Key="Image-Navbar" TargetType="Image">
|
||||
<Setter Property="Source" Value="navbar_theme.png"/>
|
||||
<Setter Property="Aspect" Value="AspectFill"/>
|
||||
<Setter Property="Grid.ColumnSpan" Value="2"/>
|
||||
</Style>
|
||||
|
||||
<!--TabbedPage-->
|
||||
<Style x:Key="TabbedPageStyle" TargetType="TabbedPage">
|
||||
<Setter Property="BarBackgroundColor" Value="White"/>
|
||||
<Setter Property="UnselectedTabColor" Value="DimGray"/>
|
||||
<Setter Property="SelectedTabColor" Value="{x:DynamicResource primary-back-title-color}"/>
|
||||
<Setter Property="android:TabbedPage.ToolbarPlacement" Value="Default"/>
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
19
SharedBusinessLogic/View/Themes/ShareeBike.xaml.cs
Normal file
19
SharedBusinessLogic/View/Themes/ShareeBike.xaml.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using ShareeBike.View.Themes;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace ShareeBike.Themes
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class ShareeBike : ResourceDictionary, ITheme
|
||||
{
|
||||
public const string OPERATORINFO = "sharee.bike";
|
||||
|
||||
public ShareeBike()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public string OperatorInfo => OPERATORINFO;
|
||||
}
|
||||
}
|
175
SharedBusinessLogic/View/WebViewHelper.cs
Normal file
175
SharedBusinessLogic/View/WebViewHelper.cs
Normal file
|
@ -0,0 +1,175 @@
|
|||
using System.Linq;
|
||||
using Serilog;
|
||||
using ShareeBike.Model.Device;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace ShareeBike.View
|
||||
{
|
||||
public static class WebViewHelper
|
||||
{
|
||||
/// <summary> Rountes request to browser if internal URI was detected or displays link in app otherwise. </summary>
|
||||
/// <param name="sender">Sender of the event.</param>
|
||||
/// <param name="eventArgs">Event arguments</param>
|
||||
public static void SelectDisplayTarget(object sender, WebNavigatingEventArgs eventArgs)
|
||||
{
|
||||
if (!eventArgs.Url.ToUpper().StartsWith("HTTP"))
|
||||
{
|
||||
// An internal link was detected.
|
||||
// Stay inside WebView
|
||||
eventArgs.Cancel = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not navigate outside the document on web view.
|
||||
eventArgs.Cancel = true;
|
||||
// Open external link in browser.
|
||||
DependencyService.Get<IExternalBrowserService>().OpenUrl(eventArgs.Url);
|
||||
}
|
||||
|
||||
/// <summary> Routes request to broswer to download pdf- documents or displays link in app otherwise. </summary>
|
||||
/// <param name="sender">Sender of the event.</param>
|
||||
/// <param name="eventArgs">Event arguments</param>
|
||||
public static void SetBusyAndDisplayOrDownload(object sender, WebNavigatingEventArgs eventArgs)
|
||||
{
|
||||
if (!eventArgs.Url.ToUpper().EndsWith(".PDF"))
|
||||
{
|
||||
// Stay inside web view except for downloading pdf- files.
|
||||
SetBusy(sender);
|
||||
eventArgs.Cancel = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not navigate outside the document on web view.
|
||||
eventArgs.Cancel = true;
|
||||
// Open external link in browser.
|
||||
DependencyService.Get<IExternalBrowserService>().OpenUrl(eventArgs.Url);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables WebView and shows ActivityIndicator.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Prerequisites: Both WebView and ActivityInicator must be located on the same Grid object.
|
||||
/// </remarks>
|
||||
/// <param name="sender"></param>
|
||||
private static void SetBusy(object sender)
|
||||
{
|
||||
if (!(sender is WebView webView))
|
||||
{
|
||||
// Nothing to do if sender is not a web view.
|
||||
Log.Error($"Unexpected call of {nameof(SetBusy)} detected. Argument must not be of type {sender.GetType()}.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(webView.Parent is Grid grid))
|
||||
{
|
||||
// Nothing to do if web view is not located on grid.
|
||||
Log.Error($"Unexpected call of {nameof(SetBusy)} detected. Parent of argument must not be of type {webView.Parent.GetType()}.");
|
||||
return;
|
||||
}
|
||||
|
||||
grid.IsEnabled = false;
|
||||
|
||||
var indicator = grid.Children.OfType<ActivityIndicator>().FirstOrDefault();
|
||||
if (indicator == null)
|
||||
{
|
||||
// Nothing to do if there is not activity indicator.
|
||||
Log.Error($"Unexpected call of {nameof(SetBusy)} detected. No activity indicator found.");
|
||||
return;
|
||||
}
|
||||
|
||||
indicator.IsVisible = true;
|
||||
indicator.IsRunning = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables WebView and hides ActivityIndicator and sets error text to WebView in case an error occurred.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Prerequisites: Both WebView and ActivityInicator must be located on the same Grid object.
|
||||
/// </remarks>
|
||||
/// <param name="htmlErrorMessage">HTML showing an error message.</param>
|
||||
public static void SetIdleAndHandleError(
|
||||
object sender,
|
||||
WebNavigatedEventArgs eventArgs,
|
||||
string htmlErrorMessage)
|
||||
{
|
||||
if (!(sender is WebView webView))
|
||||
{
|
||||
// Nothing to do if sender is not a web view.
|
||||
Log.Error($"Unexpected call of {nameof(SetIdleAndHandleError)} detected. Argument must not be of type {sender.GetType()}.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(webView.Parent is Grid grid))
|
||||
{
|
||||
// Nothing to do if web view is not located on grid.
|
||||
Log.Error($"Unexpected call of {nameof(SetIdleAndHandleError)} detected. Parent of argument must not be of type {webView.Parent.GetType()}.");
|
||||
return;
|
||||
}
|
||||
|
||||
var indicator = grid.Children.OfType<ActivityIndicator>().FirstOrDefault();
|
||||
if (indicator == null)
|
||||
{
|
||||
// Nothing to do if there is not activity indicator.
|
||||
Log.Error($"Unexpected call of {nameof(SetIdleAndHandleError)} detected. No activity indicator found.");
|
||||
}
|
||||
|
||||
if (eventArgs.Result == WebNavigationResult.Success)
|
||||
{
|
||||
// Uri could be loaded successfully.
|
||||
grid.IsEnabled = true;
|
||||
if (indicator != null)
|
||||
{
|
||||
indicator.IsVisible = false;
|
||||
indicator.IsRunning = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Navigation failed.
|
||||
Log.Error("Navigation did not succeed.{@Event}{@Sender}", eventArgs, sender);
|
||||
webView.Source = new HtmlWebViewSource
|
||||
{
|
||||
Html = !string.IsNullOrEmpty(htmlErrorMessage) ? htmlErrorMessage : $"Navigation to {eventArgs.Url} failed."
|
||||
};
|
||||
|
||||
grid.IsEnabled = true;
|
||||
if (indicator != null)
|
||||
{
|
||||
indicator.IsVisible = false;
|
||||
indicator.IsRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets error text to WebView in case an error occurred.
|
||||
/// </summary>
|
||||
/// <param name="htmlErrorMessage">HTML showing an error message.</param>
|
||||
public static void HandleError(
|
||||
object sender,
|
||||
WebNavigatedEventArgs eventArgs,
|
||||
string htmlErrorMessage)
|
||||
{
|
||||
if (eventArgs.Result == WebNavigationResult.Success)
|
||||
{
|
||||
// Uri could be loaded successfully.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(sender is WebView webView))
|
||||
{
|
||||
// Nothing to do if sender is not a web view.
|
||||
Log.Error($"Unexpected call of {nameof(HandleError)} detected. Argument must not be of type {sender.GetType()}.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Navigation failed.
|
||||
Log.Error("Navigation did not succeed.{@Event}{@Sender}", eventArgs, sender);
|
||||
webView.Source = new HtmlWebViewSource
|
||||
{
|
||||
Html = !string.IsNullOrEmpty(htmlErrorMessage) ? htmlErrorMessage : $"Navigation to {eventArgs.Url} failed."
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue