Guilhermes

This commit is contained in:
Guilherme Gaspar
2026-03-23 17:42:36 +00:00
parent 2f1935bf94
commit 44f456eb29
57 changed files with 1916 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/GuilhermesApp/bin
/GuilhermesApp/obj

14
GuilhermesApp/App.xaml Normal file
View File

@@ -0,0 +1,14 @@
<?xml version = "1.0" encoding = "UTF-8" ?>
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:GuilhermesApp"
x:Class="GuilhermesApp.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

14
GuilhermesApp/App.xaml.cs Normal file
View File

@@ -0,0 +1,14 @@
namespace GuilhermesApp;
public partial class App : Application
{
public App()
{
InitializeComponent();
}
protected override Window CreateWindow(IActivationState? activationState)
{
return new Window(new AppShell());
}
}

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
x:Class="GuilhermesApp.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:pages="clr-namespace:GuilhermesApp.Pages"
Title="GuilhermesApp">
<ShellContent
Route="LoginPage"
ContentTemplate="{DataTemplate pages:LoginPage}"
Shell.FlyoutItemIsVisible="False"
Shell.NavBarIsVisible="False" />
<TabBar Route="MainTabs">
<Tab Title="Formulários">
<ShellContent ContentTemplate="{DataTemplate pages:FormsMenuPage}" />
</Tab>
<Tab Title="Chat">
<ShellContent ContentTemplate="{DataTemplate pages:ChatPage}" />
</Tab>
<Tab Title="Perfil">
<ShellContent ContentTemplate="{DataTemplate pages:ProfilePage}" />
</Tab>
<Tab Title="Sensor">
<ShellContent ContentTemplate="{DataTemplate pages:SensorPage}" />
</Tab>
</TabBar>
</Shell>

View File

@@ -0,0 +1,18 @@
using GuilhermesApp.Pages;
namespace GuilhermesApp;
public partial class AppShell : Shell
{
public AppShell()
{
InitializeComponent();
// Registar rotas para navegação
Routing.RegisterRoute(nameof(RegisterPage), typeof(RegisterPage));
Routing.RegisterRoute(nameof(ProfilePage), typeof(ProfilePage));
Routing.RegisterRoute(nameof(FormsHistoryPage), typeof(FormsHistoryPage));
Routing.RegisterRoute(nameof(NewFormPage), typeof(NewFormPage));
Routing.RegisterRoute(nameof(FormsMenuPage), typeof(FormsMenuPage));
}
}

View File

@@ -0,0 +1,72 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<MauiEnableXamlCBindingWithSourceCompilation>true</MauiEnableXamlCBindingWithSourceCompilation>
<TargetFrameworks>net9.0-android;net9.0-ios;net9.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net9.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);net9.0-tizen</TargetFrameworks> -->
<!-- Note for MacCatalyst:
The default runtime is maccatalyst-x64, except in Release config, in which case the default is maccatalyst-x64;maccatalyst-arm64.
When specifying both architectures, use the plural <RuntimeIdentifiers> instead of the singular <RuntimeIdentifier>.
The Mac App Store will NOT accept apps with ONLY maccatalyst-arm64 indicated;
either BOTH runtimes must be indicated or ONLY macatalyst-x64. -->
<!-- For example: <RuntimeIdentifiers>maccatalyst-x64;maccatalyst-arm64</RuntimeIdentifiers> -->
<OutputType>Exe</OutputType>
<RootNamespace>GuilhermesApp</RootNamespace>
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<!-- Display name -->
<ApplicationTitle>GuilhermesApp</ApplicationTitle>
<!-- App Identifier -->
<ApplicationId>com.companyname.guilhermesapp</ApplicationId>
<!-- Versions -->
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<ApplicationVersion>1</ApplicationVersion>
<!-- To develop, package, and publish an app to the Microsoft Store, see: https://aka.ms/MauiTemplateUnpackaged -->
<WindowsPackageType>None</WindowsPackageType>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">15.0</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.5</SupportedOSPlatformVersion>
</PropertyGroup>
<ItemGroup>
<!-- App Icon -->
<MauiIcon Include="Resources\AppIcon\appicon.svg" ForegroundFile="Resources\AppIcon\appiconfg.svg" Color="#512BD4" />
<!-- Splash Screen -->
<MauiSplashScreen Include="Resources\Splash\splash.svg" Color="#512BD4" BaseSize="128,128" />
<!-- Images -->
<MauiImage Include="Resources\Images\*" />
<MauiImage Update="Resources\Images\dotnet_bot.png" Resize="True" BaseSize="300,185" />
<!-- Custom Fonts -->
<MauiFont Include="Resources\Fonts\*" />
<!-- Raw Assets (also remove the "Resources\Raw" prefix) -->
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="FirebaseAuthentication.net" Version="4.1.0" />
<PackageReference Include="FirebaseDatabase.net" Version="5.0.0" />
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="9.0.9" />
<PackageReference Include="MQTTnet" Version="5.1.0.1559" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ActiveDebugFramework>net9.0-windows10.0.19041.0</ActiveDebugFramework>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,24 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GuilhermesApp", "GuilhermesApp.csproj", "{375AEA15-E9B8-87B0-1ED4-3F429D79CEA1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{375AEA15-E9B8-87B0-1ED4-3F429D79CEA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{375AEA15-E9B8-87B0-1ED4-3F429D79CEA1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{375AEA15-E9B8-87B0-1ED4-3F429D79CEA1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{375AEA15-E9B8-87B0-1ED4-3F429D79CEA1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {478009F4-C3B4-4F0D-AD10-73A3DE68D439}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,27 @@
using Firebase.Auth;
using Firebase.Auth.Providers;
using Firebase.Database;
namespace GuilhermesApp.Helpers;
public class FirebaseService
{
private const string WebApiKey = "AIzaSyBU367GLutI5FiXf5JvrwIMWu0jJoDGl9k";
private const string DatabaseUrl = "https://guilhermesapp-default-rtdb.europe-west1.firebasedatabase.app/";
public FirebaseAuthClient AuthClient { get; private set; }
public FirebaseClient DbClient { get; private set; }
public FirebaseService()
{
var config = new FirebaseAuthConfig
{
ApiKey = WebApiKey,
AuthDomain = "guilhermesapp.firebaseapp.com",
Providers = new FirebaseAuthProvider[] { new EmailProvider() }
};
AuthClient = new FirebaseAuthClient(config);
DbClient = new FirebaseClient(DatabaseUrl);
}
}

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="GuilhermesApp.MainPage">
<ScrollView>
<VerticalStackLayout
Padding="30,0"
Spacing="25">
<Image
Source="dotnet_bot.png"
HeightRequest="185"
Aspect="AspectFit"
SemanticProperties.Description="dot net bot in a hovercraft number nine" />
<Label
Text="Hello, World!"
Style="{StaticResource Headline}"
SemanticProperties.HeadingLevel="Level1" />
<Label
Text="Welcome to &#10;.NET Multi-platform App UI"
Style="{StaticResource SubHeadline}"
SemanticProperties.HeadingLevel="Level2"
SemanticProperties.Description="Welcome to dot net Multi platform App U I" />
<Button
x:Name="CounterBtn"
Text="Click me"
SemanticProperties.Hint="Counts the number of times you click"
Clicked="OnCounterClicked"
HorizontalOptions="Fill" />
</VerticalStackLayout>
</ScrollView>
</ContentPage>

View File

@@ -0,0 +1,23 @@
namespace GuilhermesApp;
public partial class MainPage : ContentPage
{
int count = 0;
public MainPage()
{
InitializeComponent();
}
private void OnCounterClicked(object? sender, EventArgs e)
{
count++;
if (count == 1)
CounterBtn.Text = $"Clicked {count} time";
else
CounterBtn.Text = $"Clicked {count} times";
SemanticScreenReader.Announce(CounterBtn.Text);
}
}

View File

@@ -0,0 +1,24 @@
using Microsoft.Extensions.Logging;
namespace GuilhermesApp;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
#if DEBUG
builder.Logging.AddDebug();
#endif
return builder.Build();
}
}

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="GuilhermesApp.Pages.ChatPage"
Shell.NavBarIsVisible="False"
Title="Chat">
<Grid RowDefinitions="*, Auto" Padding="15">
<ScrollView x:Name="ChatScroll" Grid.Row="0">
<VerticalStackLayout x:Name="ChatStack" Spacing="10" Padding="0,0,0,15" />
</ScrollView>
<Grid Grid.Row="1" ColumnDefinitions="*, Auto" ColumnSpacing="10" Margin="0,10,0,0">
<Entry x:Name="MensagemEntry" Grid.Column="0" Placeholder="Escreve aqui..." ReturnType="Send" />
<Button x:Name="EnviarBtn" Grid.Column="1" Text="Enviar" Clicked="OnEnviarClicked" />
</Grid>
</Grid>
</ContentPage>

View File

@@ -0,0 +1,94 @@
using System.Text;
using System.Text.Json;
using Microsoft.Maui.Controls.Shapes;
namespace GuilhermesApp.Pages;
public partial class ChatPage : ContentPage
{
private const string ApiKey = "AIzaSyBfQIHWK57GDhk4N-xYg_bEVWyQ6X1EmwA";
private const string Url = $"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={ApiKey}";
private HttpClient _httpClient = new HttpClient();
public ChatPage()
{
InitializeComponent();
AdicionarBalao("Olá! Sou o assistente da GuilhermesApp. Como te posso ajudar hoje?", false);
}
private async void OnEnviarClicked(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(MensagemEntry.Text)) return;
string textoUser = MensagemEntry.Text;
MensagemEntry.Text = "";
AdicionarBalao(textoUser, true);
EnviarBtn.IsEnabled = false;
try
{
var requestBody = new { contents = new[] { new { parts = new[] { new { text = textoUser } } } } };
var content = new StringContent(JsonSerializer.Serialize(requestBody), Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync(Url, content);
var json = await response.Content.ReadAsStringAsync();
using var doc = JsonDocument.Parse(json);
// Verifica se o pedido teve sucesso
if (response.IsSuccessStatusCode)
{
var respostaBot = doc.RootElement
.GetProperty("candidates")[0]
.GetProperty("content")
.GetProperty("parts")[0]
.GetProperty("text").GetString();
AdicionarBalao(respostaBot, false);
}
else
{
// Lê a mensagem de erro real da Google
string erroGoogle = "Erro desconhecido.";
if (doc.RootElement.TryGetProperty("error", out var errorElement) &&
errorElement.TryGetProperty("message", out var msgElement))
{
erroGoogle = msgElement.GetString() ?? "Erro desconhecido";
}
AdicionarBalao($"A API recusou: {erroGoogle}", false);
}
}
catch (Exception ex)
{
AdicionarBalao($"Erro interno: {ex.Message}", false);
}
EnviarBtn.IsEnabled = true;
}
// Cria os balões visuais
private void AdicionarBalao(string? texto, bool isUser)
{
var label = new Label
{
Text = texto,
TextColor = Colors.Black,
Padding = 15
};
var border = new Border
{
StrokeShape = new RoundRectangle { CornerRadius = new CornerRadius(15) },
BackgroundColor = isUser ? Color.FromArgb("#D1E8FF") : Color.FromArgb("#F3F4F6"),
Stroke = Colors.Transparent,
Margin = new Thickness(isUser ? 50 : 0, 5, isUser ? 0 : 50, 5),
HorizontalOptions = isUser ? LayoutOptions.End : LayoutOptions.Start,
Content = label
};
ChatStack.Children.Add(border);
// Faz scroll automático para o fundo
ChatScroll.ScrollToAsync(ChatStack, ScrollToPosition.End, true);
}
}

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="GuilhermesApp.Pages.FormsHistoryPage"
Shell.NavBarIsVisible="False"
xmlns:local="clr-namespace:GuilhermesApp.Pages"
Title="O Meu Histórico">
<VerticalStackLayout Padding="20" Spacing="15">
<Label Text="Registos Anteriores" FontSize="24" FontAttributes="Bold" HorizontalOptions="Center" />
<ActivityIndicator x:Name="LoadingIndicator" IsRunning="True" Color="Blue" HorizontalOptions="Center" />
<Label x:Name="EmptyLabel" Text="Ainda não tens formulários submetidos." IsVisible="False" HorizontalOptions="Center" TextColor="Black" />
<CollectionView x:Name="FormsCollection" IsVisible="False" SelectionMode="Single" SelectionChanged="OnFormSelected">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="local:FormResult">
<Border Margin="0,5" Padding="15" StrokeShape="RoundRectangle 10" BackgroundColor="#F3F4F6" Stroke="Transparent">
<VerticalStackLayout Spacing="5">
<Label Text="{Binding Data}" FontAttributes="Bold" FontSize="16" TextColor="Black" />
<Label Text="{Binding Humor, StringFormat='Humor: {0}'}" TextColor="Black"/>
<Label Text="{Binding Stress, StringFormat='Nível de Stress: {0}/10'}" TextColor="Black"/>
<Label Text="Clica para ver tudo..." FontSize="12" TextColor="Black" Margin="0,5,0,0" />
</VerticalStackLayout>
</Border>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</VerticalStackLayout>
</ContentPage>

View File

@@ -0,0 +1,83 @@
using GuilhermesApp.Helpers;
using Firebase.Database.Query;
namespace GuilhermesApp.Pages;
public partial class FormsHistoryPage : ContentPage
{
private FirebaseService _firebaseService = new FirebaseService();
public FormsHistoryPage()
{
InitializeComponent();
}
protected override async void OnAppearing()
{
base.OnAppearing();
await CarregarHistorico();
}
private async Task CarregarHistorico()
{
try
{
var user = _firebaseService.AuthClient.User;
if (user == null) return;
// Vai buscar todos os registos na pasta Forms do utilizador
var forms = await _firebaseService.DbClient
.Child("Forms")
.Child(user.Uid)
.OnceAsync<FormResult>();
LoadingIndicator.IsRunning = false;
LoadingIndicator.IsVisible = false;
if (forms.Count == 0)
{
EmptyLabel.IsVisible = true;
}
else
{
// Converte os dados, inverte a ordem (para o mais recente ficar no topo) e mostra na lista
var listaOrdenada = forms.Select(f => f.Object).Reverse().ToList();
FormsCollection.ItemsSource = listaOrdenada;
FormsCollection.IsVisible = true;
}
}
catch (Exception)
{
LoadingIndicator.IsRunning = false;
LoadingIndicator.IsVisible = false;
await DisplayAlert("Erro", "Não foi possível carregar o histórico.", "OK");
}
}
private async void OnFormSelected(object sender, SelectionChangedEventArgs e)
{
if (e.CurrentSelection.FirstOrDefault() is FormResult form)
{
string exercicio = form.FezExercicio ? "Sim" : "Não";
string mensagem = $"Humor: {form.Humor}\nStress: {form.Stress}/10\nSono: {form.Sono}\nExercício: {exercicio}\nNotas: {form.Notas}";
await DisplayAlert($"Detalhes de {form.Data}", mensagem, "Fechar");
// Limpa a seleção para permitir clicar novamente no mesmo
((CollectionView)sender).SelectedItem = null;
}
}
}
// Classe de apoio para mapear os dados do Firebase
public class FormResult
{
public string? Data { get; set; }
public string? Humor { get; set; }
public double Stress { get; set; }
public string? Sono { get; set; }
public bool FezExercicio { get; set; }
public string? Notas { get; set; }
}

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="GuilhermesApp.Pages.FormsMenuPage"
Shell.NavBarIsVisible="False"
Title="Formulários">
<VerticalStackLayout Spacing="20" Padding="30" VerticalOptions="Center">
<Label Text="Gestão de Formulários" FontSize="28" HorizontalOptions="Center" FontAttributes="Bold" Margin="0,0,0,20" />
<Button Text="Preencher Novo Formulário" Clicked="OnNewFormClicked" HeightRequest="60" />
<Button Text="Ver Histórico" Clicked="OnHistoryClicked" HeightRequest="60" />
</VerticalStackLayout>
</ContentPage>

View File

@@ -0,0 +1,19 @@
namespace GuilhermesApp.Pages;
public partial class FormsMenuPage : ContentPage
{
public FormsMenuPage()
{
InitializeComponent();
}
private async void OnNewFormClicked(object sender, EventArgs e)
{
await Shell.Current.GoToAsync(nameof(NewFormPage));
}
private async void OnHistoryClicked(object sender, EventArgs e)
{
await Shell.Current.GoToAsync(nameof(FormsHistoryPage));
}
}

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="GuilhermesApp.Pages.LoginPage"
Shell.NavBarIsVisible="False"
Shell.FlyoutBehavior="Disabled"
Title="Login">
<ScrollView>
<VerticalStackLayout Spacing="20" Padding="30" VerticalOptions="Center">
<Image Source="logo.png" HeightRequest="240" HorizontalOptions="Center" />
<Label Text="Bem-vindo!" FontSize="32" HorizontalOptions="Center" FontAttributes="Bold" />
<Entry x:Name="EmailEntry" Placeholder="Email" Keyboard="Email" />
<Entry x:Name="PasswordEntry" Placeholder="Password" IsPassword="True" />
<Button Text="Entrar" Clicked="OnLoginClicked" />
<Label Text="Ainda não tens conta? Regista-te"
TextColor="#FF888890"
TextDecorations="Underline"
HorizontalOptions="Center">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="OnRegisterClicked" />
</Label.GestureRecognizers>
</Label>
</VerticalStackLayout>
</ScrollView>
</ContentPage>

View File

@@ -0,0 +1,42 @@
using GuilhermesApp.Helpers;
namespace GuilhermesApp.Pages;
public partial class LoginPage : ContentPage
{
private FirebaseService _firebaseService = new FirebaseService();
public LoginPage()
{
InitializeComponent();
}
private async void OnLoginClicked(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(EmailEntry.Text) || string.IsNullOrWhiteSpace(PasswordEntry.Text))
{
await DisplayAlert("Erro", "Preenche o email e a password.", "OK");
return;
}
try
{
// Tenta fazer o login no Firebase
var user = await _firebaseService.AuthClient.SignInWithEmailAndPasswordAsync(EmailEntry.Text, PasswordEntry.Text);
// Se correr bem, vai para a página de Perfil
// O "//" define a HomePage como a nova raiz e impede de voltar atrás
await Shell.Current.GoToAsync("//MainTabs");
}
catch (Exception)
{
await DisplayAlert("Erro", "Login falhou. Verifica as credenciais.", "OK");
}
}
private async void OnRegisterClicked(object sender, EventArgs e)
{
// Vai para a página de registo
await Shell.Current.GoToAsync(nameof(RegisterPage));
}
}

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="GuilhermesApp.Pages.NewFormPage"
Shell.NavBarIsVisible="False"
Title="Novo Formulário">
<ScrollView>
<VerticalStackLayout Spacing="20" Padding="30">
<Label Text="Bem-estar Diário" FontSize="24" FontAttributes="Bold" HorizontalOptions="Center" />
<Label Text="1. Como te sentes hoje?" FontAttributes="Bold" />
<Picker x:Name="HumorPicker" Title="Seleciona uma opção">
<Picker.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Muito Bem</x:String>
<x:String>Bem</x:String>
<x:String>Neutro</x:String>
<x:String>Mal</x:String>
<x:String>Muito Mal</x:String>
</x:Array>
</Picker.ItemsSource>
</Picker>
<Label Text="2. Nível de stress (1 a 10)?" FontAttributes="Bold" />
<Slider x:Name="StressSlider" Minimum="1" Maximum="10" Value="5" />
<Label x:DataType="Slider" Text="{Binding Source={x:Reference StressSlider}, Path=Value, StringFormat='{0:F0}'}" HorizontalOptions="Center" />
<Label Text="3. Dormiste bem?" FontAttributes="Bold" />
<Picker x:Name="SonoPicker" Title="Seleciona uma opção">
<Picker.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Sim, perfeitamente</x:String>
<x:String>Mais ou menos</x:String>
<x:String>Não, dormi mal</x:String>
</x:Array>
</Picker.ItemsSource>
</Picker>
<Label Text="4. Fizeste exercício hoje?" FontAttributes="Bold" />
<Switch x:Name="ExercicioSwitch" HorizontalOptions="Start" />
<Label Text="5. Notas adicionais:" FontAttributes="Bold" />
<Entry x:Name="NotasEntry" Placeholder="Escreve aqui..." />
<Button Text="Submeter" Clicked="OnSubmitClicked" Margin="0,20,0,0" />
</VerticalStackLayout>
</ScrollView>
</ContentPage>

View File

@@ -0,0 +1,56 @@
using GuilhermesApp.Helpers;
using Firebase.Database.Query;
namespace GuilhermesApp.Pages;
public partial class NewFormPage : ContentPage
{
private FirebaseService _firebaseService = new FirebaseService();
public NewFormPage()
{
InitializeComponent();
}
private async void OnSubmitClicked(object sender, EventArgs e)
{
// Obriga a responder a algumas
if (HumorPicker.SelectedIndex == -1 || SonoPicker.SelectedIndex == -1)
{
await DisplayAlert("Erro", "Responde pelo menos às perguntas de humor e sono.", "OK");
return;
}
try
{
var user = _firebaseService.AuthClient.User;
if (user == null) return;
// Prepara os dados do formulário
var novoFormulario = new
{
Data = DateTime.Now.ToString("dd/MM/yyyy HH:mm"),
Humor = HumorPicker.SelectedItem.ToString(),
Stress = Math.Round(StressSlider.Value),
Sono = SonoPicker.SelectedItem.ToString(),
FezExercicio = ExercicioSwitch.IsToggled,
Notas = string.IsNullOrWhiteSpace(NotasEntry.Text) ? "Sem notas" : NotasEntry.Text
};
// Guarda na Realtime Database na pasta "Forms" -> "ID do Utilizador"
await _firebaseService.DbClient
.Child("Forms")
.Child(user.Uid)
.PostAsync(novoFormulario); // PostAsync cria um novo registo na lista
await DisplayAlert("Sucesso", "Formulário submetido e guardado!", "OK");
// Volta à página anterior
await Shell.Current.GoToAsync("..");
}
catch (Exception ex)
{
await DisplayAlert("Erro", $"Não foi possível guardar. Erro: {ex.Message}", "OK");
}
}
}

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="GuilhermesApp.Pages.ProfilePage"
Shell.NavBarIsVisible="False"
Title="Perfil">
<VerticalStackLayout Spacing="20" Padding="30" VerticalOptions="Center">
<Label Text="O Meu Perfil" FontSize="32" HorizontalOptions="Center" FontAttributes="Bold" />
<ActivityIndicator x:Name="LoadingIndicator" IsRunning="True" HorizontalOptions="Center" Color="Blue" />
<VerticalStackLayout x:Name="ProfileInfoLayout" IsVisible="False" Spacing="10" HorizontalOptions="Center">
<Label x:Name="NomeLabel" FontSize="22" FontAttributes="Bold" HorizontalOptions="Center" />
<Label x:Name="EmailLabel" FontSize="16" TextColor="Gray" HorizontalOptions="Center" />
<Label x:Name="TelemovelLabel" FontSize="16" HorizontalOptions="Center" />
<Label x:Name="GeneroLabel" FontSize="16" HorizontalOptions="Center" />
</VerticalStackLayout>
<Button Text="Terminar Sessão" Clicked="OnLogoutClicked" BackgroundColor="Red" TextColor="White" Margin="0,30,0,0" />
</VerticalStackLayout>
</ContentPage>

View File

@@ -0,0 +1,70 @@
using GuilhermesApp.Helpers;
using Firebase.Database.Query;
namespace GuilhermesApp.Pages;
public partial class ProfilePage : ContentPage
{
private FirebaseService _firebaseService = new FirebaseService();
public ProfilePage()
{
InitializeComponent();
}
// Este método corre sempre que a página aparece no ecrã
protected override async void OnAppearing()
{
base.OnAppearing();
await CarregarPerfil();
}
private async Task CarregarPerfil()
{
try
{
var user = _firebaseService.AuthClient.User;
if (user != null)
{
// Vai buscar os dados à Realtime Database
var perfil = await _firebaseService.DbClient
.Child("Users")
.Child(user.Uid)
.OnceSingleAsync<UserProfile>();
if (perfil != null)
{
NomeLabel.Text = perfil.Nome;
EmailLabel.Text = perfil.Email;
TelemovelLabel.Text = $"Telemóvel: {perfil.Telemovel}";
GeneroLabel.Text = $"Género: {perfil.Genero}";
// Esconde o loading e mostra os dados
LoadingIndicator.IsRunning = false;
LoadingIndicator.IsVisible = false;
ProfileInfoLayout.IsVisible = true;
}
}
}
catch (Exception)
{
await DisplayAlert("Erro", "Não foi possível carregar o perfil.", "OK");
}
}
private async void OnLogoutClicked(object sender, EventArgs e)
{
_firebaseService.AuthClient.SignOut();
// Volta para o Login e limpa o histórico
await Shell.Current.GoToAsync("//LoginPage");
}
}
// Classe simples no final do ficheiro para ajudar a ler os dados do Firebase
public class UserProfile
{
public string? Nome { get; set; }
public string? Email { get; set; }
public string? Telemovel { get; set; }
public string? Genero { get; set; }
}

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="GuilhermesApp.Pages.RegisterPage"
Shell.NavBarIsVisible="False"
Shell.FlyoutBehavior="Disabled"
Title="Registar">
<ScrollView>
<VerticalStackLayout Spacing="20" Padding="30" VerticalOptions="Center">
<Label Text="Criar Conta" FontSize="32" HorizontalOptions="Center" FontAttributes="Bold" />
<Entry x:Name="NomeEntry" Placeholder="Nome Completo" />
<Entry x:Name="TelemovelEntry" Placeholder="Telemóvel" Keyboard="Telephone" />
<Picker x:Name="GeneroPicker" Title="Seleciona o Género">
<Picker.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Masculino</x:String>
<x:String>Feminino</x:String>
<x:String>Outro</x:String>
<x:String>Prefiro não dizer</x:String>
</x:Array>
</Picker.ItemsSource>
</Picker>
<Entry x:Name="EmailEntry" Placeholder="Email" Keyboard="Email" />
<Entry x:Name="PasswordEntry" Placeholder="Password (mín. 6 caracteres)" IsPassword="True" />
<Entry x:Name="ConfirmPasswordEntry" Placeholder="Confirmar Password" IsPassword="True" />
<Button Text="Registar" Clicked="OnRegisterAccountClicked" />
</VerticalStackLayout>
</ScrollView>
</ContentPage>

View File

@@ -0,0 +1,68 @@
using GuilhermesApp.Helpers;
using Firebase.Database.Query;
namespace GuilhermesApp.Pages;
public partial class RegisterPage : ContentPage
{
private FirebaseService _firebaseService = new FirebaseService();
public RegisterPage()
{
InitializeComponent();
}
private async void OnRegisterAccountClicked(object sender, EventArgs e)
{
// 1. Validar se está tudo preenchido
if (string.IsNullOrWhiteSpace(NomeEntry.Text) || string.IsNullOrWhiteSpace(TelemovelEntry.Text) ||
GeneroPicker.SelectedIndex == -1 || string.IsNullOrWhiteSpace(EmailEntry.Text) ||
string.IsNullOrWhiteSpace(PasswordEntry.Text))
{
await DisplayAlert("Erro", "Preenche todos os campos.", "OK");
return;
}
// 2. Validar passwords
if (PasswordEntry.Text != ConfirmPasswordEntry.Text)
{
await DisplayAlert("Erro", "As passwords não coincidem.", "OK");
return;
}
if (PasswordEntry.Text.Length < 6)
{
await DisplayAlert("Erro", "A password tem de ter pelo menos 6 caracteres.", "OK");
return;
}
try
{
// 3. Cria a conta na Autenticação
var userCredential = await _firebaseService.AuthClient.CreateUserWithEmailAndPasswordAsync(EmailEntry.Text, PasswordEntry.Text);
var uid = userCredential.User.Uid; // O ID único do utilizador
// 4. Guarda os restantes dados na Realtime Database, na pasta "Users"
await _firebaseService.DbClient
.Child("Users")
.Child(uid)
.PutAsync(new
{
Nome = NomeEntry.Text,
Telemovel = TelemovelEntry.Text,
Genero = GeneroPicker.SelectedItem.ToString(),
Email = EmailEntry.Text
});
await DisplayAlert("Sucesso", "Conta criada com sucesso!", "OK");
// Volta para a página de Login
await Shell.Current.GoToAsync("..");
}
catch (Exception ex)
{
// Mostra o erro exato que vem do Firebase
await DisplayAlert("Erro", $"Não foi possível criar a conta. Detalhe: {ex.Message}", "OK");
}
}
}

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="GuilhermesApp.Pages.SensorPage"
Shell.NavBarIsVisible="False"
Title="Sensor">
<VerticalStackLayout Spacing="30" Padding="30" VerticalOptions="Center">
<Label Text="Controlo ESP32-C6" FontSize="28" FontAttributes="Bold" HorizontalOptions="Center" />
<Border Padding="20" StrokeShape="RoundRectangle 15" BackgroundColor="#F3F4F6" Stroke="Transparent">
<VerticalStackLayout Spacing="10" HorizontalOptions="Center">
<Label Text="Estado do LED" FontSize="18" HorizontalOptions="Center" TextColor="Black"/>
<Button x:Name="LedBtn" Text="LIGAR LED" Clicked="OnLedClicked" BackgroundColor="DarkSlateGray" TextColor="White"/>
</VerticalStackLayout>
</Border>
<Border Padding="20" StrokeShape="RoundRectangle 15" BackgroundColor="#D1E8FF" Stroke="Transparent">
<VerticalStackLayout Spacing="10" HorizontalOptions="Center">
<Label Text="Botão no Arduino" FontSize="18" HorizontalOptions="Center" TextColor="Black"/>
<Label x:Name="StatusLabel" Text="A aguardar sinal..." FontAttributes="Bold" FontSize="20" TextColor="Black" HorizontalOptions="Center" />
</VerticalStackLayout>
</Border>
</VerticalStackLayout>
</ContentPage>

View File

@@ -0,0 +1,83 @@
using MQTTnet;
using System.Text;
using System.Buffers;
namespace GuilhermesApp.Pages;
public partial class SensorPage : ContentPage
{
private IMqttClient? _mqttClient;
private MqttClientOptions? _options;
private bool _isLedOn = false;
public SensorPage()
{
InitializeComponent();
ConfigurarMqtt();
}
private async void ConfigurarMqtt()
{
try
{
// TENTATIVA A: MqttClientFactory (Novo padrão em algumas versões v5)
// Se der erro aqui, tenta mudar para: var factory = new MqttFactory();
var factory = new MqttClientFactory();
_mqttClient = factory.CreateMqttClient();
_options = new MqttClientOptionsBuilder()
.WithTcpServer("broker.hivemq.com", 1883)
.Build();
_mqttClient.ApplicationMessageReceivedAsync += e =>
{
// Extração manual de bytes para evitar o erro do ToArray
var buffer = e.ApplicationMessage.Payload;
byte[] payloadBytes = new byte[buffer.Length];
buffer.CopyTo(payloadBytes);
string payload = Encoding.UTF8.GetString(payloadBytes);
MainThread.BeginInvokeOnMainThread(() =>
{
if (payload == "PRESSIONADO")
{
StatusLabel.Text = $"Último clique: {DateTime.Now:HH:mm:ss}";
StatusLabel.TextColor = Colors.Green;
}
});
return Task.CompletedTask;
};
await _mqttClient.ConnectAsync(_options);
await _mqttClient.SubscribeAsync("guilherme/app/botao");
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Erro crítico MQTT: {ex.Message}");
}
}
private async void OnLedClicked(object sender, EventArgs e)
{
if (_mqttClient == null || !_mqttClient.IsConnected)
{
await DisplayAlert("Erro", "O MQTT não está ligado.", "OK");
return;
}
_isLedOn = !_isLedOn;
string comando = _isLedOn ? "ON" : "OFF";
var message = new MqttApplicationMessageBuilder()
.WithTopic("guilherme/app/led")
.WithPayload(comando)
.Build();
await _mqttClient.PublishAsync(message);
LedBtn.Text = _isLedOn ? "DESLIGAR LED" : "LIGAR LED";
LedBtn.BackgroundColor = _isLedOn ? Colors.Red : Colors.DarkSlateGray;
}
}

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true"></application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

View File

@@ -0,0 +1,10 @@
using Android.App;
using Android.Content.PM;
using Android.OS;
namespace GuilhermesApp;
[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
public class MainActivity : MauiAppCompatActivity
{
}

View File

@@ -0,0 +1,15 @@
using Android.App;
using Android.Runtime;
namespace GuilhermesApp;
[Application]
public class MainApplication : MauiApplication
{
public MainApplication(IntPtr handle, JniHandleOwnership ownership)
: base(handle, ownership)
{
}
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#512BD4</color>
<color name="colorPrimaryDark">#2B0B98</color>
<color name="colorAccent">#2B0B98</color>
</resources>

View File

@@ -0,0 +1,9 @@
using Foundation;
namespace GuilhermesApp;
[Register("AppDelegate")]
public class AppDelegate : MauiUIApplicationDelegate
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<!-- See https://aka.ms/maui-publish-app-store#add-entitlements for more information about adding entitlements.-->
<dict>
<!-- App Sandbox must be enabled to distribute a MacCatalyst app through the Mac App Store. -->
<key>com.apple.security.app-sandbox</key>
<true/>
<!-- When App Sandbox is enabled, this value is required to open outgoing network connections. -->
<key>com.apple.security.network.client</key>
<true/>
</dict>
</plist>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- The Mac App Store requires you specify if the app uses encryption. -->
<!-- Please consult https://developer.apple.com/documentation/bundleresources/information_property_list/itsappusesnonexemptencryption -->
<!-- <key>ITSAppUsesNonExemptEncryption</key> -->
<!-- Please indicate <true/> or <false/> here. -->
<!-- Specify the category for your app here. -->
<!-- Please consult https://developer.apple.com/documentation/bundleresources/information_property_list/lsapplicationcategorytype -->
<!-- <key>LSApplicationCategoryType</key> -->
<!-- <string>public.app-category.YOUR-CATEGORY-HERE</string> -->
<key>UIDeviceFamily</key>
<array>
<integer>2</integer>
</array>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>XSAppIconAssets</key>
<string>Assets.xcassets/appicon.appiconset</string>
</dict>
</plist>

View File

@@ -0,0 +1,15 @@
using ObjCRuntime;
using UIKit;
namespace GuilhermesApp;
public class Program
{
// This is the main entry point of the application.
static void Main(string[] args)
{
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main(args, null, typeof(AppDelegate));
}
}

View File

@@ -0,0 +1,16 @@
using System;
using Microsoft.Maui;
using Microsoft.Maui.Hosting;
namespace GuilhermesApp;
class Program : MauiApplication
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
static void Main(string[] args)
{
var app = new Program();
app.Run(args);
}
}

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="maui-application-id-placeholder" version="0.0.0" api-version="9" xmlns="http://tizen.org/ns/packages">
<profile name="common" />
<ui-application appid="maui-application-id-placeholder" exec="GuilhermesApp.dll" multiple="false" nodisplay="false" taskmanage="true" type="dotnet" launch_mode="single">
<label>maui-application-title-placeholder</label>
<icon>maui-appicon-placeholder</icon>
<metadata key="http://tizen.org/metadata/prefer_dotnet_aot" value="true" />
</ui-application>
<shortcut-list />
<privileges>
<privilege>http://tizen.org/privilege/internet</privilege>
</privileges>
<dependencies />
<provides-appdefined-privileges />
</manifest>

View File

@@ -0,0 +1,8 @@
<maui:MauiWinUIApplication
x:Class="GuilhermesApp.WinUI.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:maui="using:Microsoft.Maui"
xmlns:local="using:GuilhermesApp.WinUI">
</maui:MauiWinUIApplication>

View File

@@ -0,0 +1,24 @@
using Microsoft.UI.Xaml;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace GuilhermesApp.WinUI;
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
public partial class App : MauiWinUIApplication
{
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
}
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap rescap">
<Identity Name="maui-package-name-placeholder" Publisher="CN=User Name" Version="0.0.0.0" />
<mp:PhoneIdentity PhoneProductId="8196308C-0687-4455-B7B6-10F85A2AC309" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
<Properties>
<DisplayName>$placeholder$</DisplayName>
<PublisherDisplayName>User Name</PublisherDisplayName>
<Logo>$placeholder$.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate" />
</Resources>
<Applications>
<Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="$targetentrypoint$">
<uap:VisualElements
DisplayName="$placeholder$"
Description="$placeholder$"
Square150x150Logo="$placeholder$.png"
Square44x44Logo="$placeholder$.png"
BackgroundColor="transparent">
<uap:DefaultTile Square71x71Logo="$placeholder$.png" Wide310x150Logo="$placeholder$.png" Square310x310Logo="$placeholder$.png" />
<uap:SplashScreen Image="$placeholder$.png" />
</uap:VisualElements>
</Application>
</Applications>
<Capabilities>
<rescap:Capability Name="runFullTrust" />
</Capabilities>
</Package>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="GuilhermesApp.WinUI.app"/>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<!-- The combination of below two tags have the following effect:
1) Per-Monitor for >= Windows 10 Anniversary Update
2) System < Windows 10 Anniversary Update
-->
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
</windowsSettings>
</application>
</assembly>

View File

@@ -0,0 +1,9 @@
using Foundation;
namespace GuilhermesApp;
[Register("AppDelegate")]
public class AppDelegate : MauiUIApplicationDelegate
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>XSAppIconAssets</key>
<string>Assets.xcassets/appicon.appiconset</string>
</dict>
</plist>

View File

@@ -0,0 +1,15 @@
using ObjCRuntime;
using UIKit;
namespace GuilhermesApp;
public class Program
{
// This is the main entry point of the application.
static void Main(string[] args)
{
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main(args, null, typeof(AppDelegate));
}
}

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
This is the minimum required version of the Apple Privacy Manifest for .NET MAUI apps.
The contents below are needed because of APIs that are used in the .NET framework and .NET MAUI SDK.
You are responsible for adding extra entries as needed for your application.
More information: https://aka.ms/maui-privacy-manifest
-->
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>C617.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>35F9.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryDiskSpace</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>E174.1</string>
</array>
</dict>
<!--
The entry below is only needed when you're using the Preferences API in your app.
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
</dict> -->
</array>
</dict>
</plist>

View File

@@ -0,0 +1,8 @@
{
"profiles": {
"Windows Machine": {
"commandName": "Project",
"nativeDebugging": false
}
}
}

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="456" height="456" viewBox="0 0 456 456" version="1.1" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="456" height="456" fill="#512BD4" />
</svg>

After

Width:  |  Height:  |  Size: 228 B

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="456" height="456" viewBox="0 0 456 456" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<path d="m 105.50037,281.60863 c -2.70293,0 -5.00091,-0.90042 -6.893127,-2.70209 -1.892214,-1.84778 -2.837901,-4.04181 -2.837901,-6.58209 0,-2.58722 0.945687,-4.80389 2.837901,-6.65167 1.892217,-1.84778 4.190197,-2.77167 6.893127,-2.77167 2.74819,0 5.06798,0.92389 6.96019,2.77167 1.93749,1.84778 2.90581,4.06445 2.90581,6.65167 0,2.54028 -0.96832,4.73431 -2.90581,6.58209 -1.89221,1.80167 -4.212,2.70209 -6.96019,2.70209 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
<path d="M 213.56111,280.08446 H 195.99044 L 149.69953,207.0544 c -1.17121,-1.84778 -2.14037,-3.76515 -2.90581,-5.75126 h -0.40578 c 0.36051,2.12528 0.54076,6.67515 0.54076,13.6496 v 65.13172 h -15.54349 v -99.36009 h 18.71925 l 44.7374,71.29798 c 1.89222,2.95695 3.1087,4.98917 3.64945,6.09751 h 0.26996 c -0.45021,-2.6325 -0.67573,-7.09015 -0.67573,-13.37293 v -64.02256 h 15.47557 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
<path d="m 289.25134,280.08446 h -54.40052 v -99.36009 h 52.23835 v 13.99669 h -36.15411 v 28.13085 h 33.31621 v 13.9271 h -33.31621 v 29.37835 h 38.31628 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
<path d="M 366.56466,194.72106 H 338.7222 v 85.3634 h -16.08423 v -85.3634 h -27.77455 v -13.99669 h 71.70124 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

View File

@@ -0,0 +1,15 @@
Any raw assets you want to be deployed with your application can be placed in
this directory (and child directories). Deployment of the asset to your application
is automatically handled by the following `MauiAsset` Build Action within your `.csproj`.
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
These files will be deployed with your package and will be accessible using Essentials:
async Task LoadMauiAsset()
{
using var stream = await FileSystem.OpenAppPackageFileAsync("AboutAssets.txt");
using var reader = new StreamReader(stream);
var contents = reader.ReadToEnd();
}

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="456" height="456" viewBox="0 0 456 456" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<path d="m 105.50037,281.60863 c -2.70293,0 -5.00091,-0.90042 -6.893127,-2.70209 -1.892214,-1.84778 -2.837901,-4.04181 -2.837901,-6.58209 0,-2.58722 0.945687,-4.80389 2.837901,-6.65167 1.892217,-1.84778 4.190197,-2.77167 6.893127,-2.77167 2.74819,0 5.06798,0.92389 6.96019,2.77167 1.93749,1.84778 2.90581,4.06445 2.90581,6.65167 0,2.54028 -0.96832,4.73431 -2.90581,6.58209 -1.89221,1.80167 -4.212,2.70209 -6.96019,2.70209 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
<path d="M 213.56111,280.08446 H 195.99044 L 149.69953,207.0544 c -1.17121,-1.84778 -2.14037,-3.76515 -2.90581,-5.75126 h -0.40578 c 0.36051,2.12528 0.54076,6.67515 0.54076,13.6496 v 65.13172 h -15.54349 v -99.36009 h 18.71925 l 44.7374,71.29798 c 1.89222,2.95695 3.1087,4.98917 3.64945,6.09751 h 0.26996 c -0.45021,-2.6325 -0.67573,-7.09015 -0.67573,-13.37293 v -64.02256 h 15.47557 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
<path d="m 289.25134,280.08446 h -54.40052 v -99.36009 h 52.23835 v 13.99669 h -36.15411 v 28.13085 h 33.31621 v 13.9271 h -33.31621 v 29.37835 h 38.31628 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
<path d="M 366.56466,194.72106 H 338.7222 v 85.3634 h -16.08423 v -85.3634 h -27.77455 v -13.99669 h 71.70124 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8" ?>
<?xaml-comp compile="true" ?>
<ResourceDictionary
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<!-- Note: For Android please see also Platforms\Android\Resources\values\colors.xml -->
<Color x:Key="Primary">#512BD4</Color>
<Color x:Key="PrimaryDark">#ac99ea</Color>
<Color x:Key="PrimaryDarkText">#242424</Color>
<Color x:Key="Secondary">#DFD8F7</Color>
<Color x:Key="SecondaryDarkText">#9880e5</Color>
<Color x:Key="Tertiary">#2B0B98</Color>
<Color x:Key="White">White</Color>
<Color x:Key="Black">Black</Color>
<Color x:Key="Magenta">#D600AA</Color>
<Color x:Key="MidnightBlue">#190649</Color>
<Color x:Key="OffBlack">#1f1f1f</Color>
<Color x:Key="Gray100">#E1E1E1</Color>
<Color x:Key="Gray200">#C8C8C8</Color>
<Color x:Key="Gray300">#ACACAC</Color>
<Color x:Key="Gray400">#919191</Color>
<Color x:Key="Gray500">#6E6E6E</Color>
<Color x:Key="Gray600">#404040</Color>
<Color x:Key="Gray900">#212121</Color>
<Color x:Key="Gray950">#141414</Color>
<SolidColorBrush x:Key="PrimaryBrush" Color="{StaticResource Primary}"/>
<SolidColorBrush x:Key="SecondaryBrush" Color="{StaticResource Secondary}"/>
<SolidColorBrush x:Key="TertiaryBrush" Color="{StaticResource Tertiary}"/>
<SolidColorBrush x:Key="WhiteBrush" Color="{StaticResource White}"/>
<SolidColorBrush x:Key="BlackBrush" Color="{StaticResource Black}"/>
<SolidColorBrush x:Key="Gray100Brush" Color="{StaticResource Gray100}"/>
<SolidColorBrush x:Key="Gray200Brush" Color="{StaticResource Gray200}"/>
<SolidColorBrush x:Key="Gray300Brush" Color="{StaticResource Gray300}"/>
<SolidColorBrush x:Key="Gray400Brush" Color="{StaticResource Gray400}"/>
<SolidColorBrush x:Key="Gray500Brush" Color="{StaticResource Gray500}"/>
<SolidColorBrush x:Key="Gray600Brush" Color="{StaticResource Gray600}"/>
<SolidColorBrush x:Key="Gray900Brush" Color="{StaticResource Gray900}"/>
<SolidColorBrush x:Key="Gray950Brush" Color="{StaticResource Gray950}"/>
</ResourceDictionary>

View File

@@ -0,0 +1,440 @@
<?xml version="1.0" encoding="UTF-8" ?>
<?xaml-comp compile="true" ?>
<ResourceDictionary
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<Style TargetType="ActivityIndicator">
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
</Style>
<Style TargetType="IndicatorView">
<Setter Property="IndicatorColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}"/>
<Setter Property="SelectedIndicatorColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray100}}"/>
</Style>
<Style TargetType="Border">
<Setter Property="Stroke" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
<Setter Property="StrokeShape" Value="Rectangle"/>
<Setter Property="StrokeThickness" Value="1"/>
</Style>
<Style TargetType="BoxView">
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" />
</Style>
<Style TargetType="Button">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource PrimaryDarkText}}" />
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource PrimaryDark}}" />
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="BorderWidth" Value="0"/>
<Setter Property="CornerRadius" Value="8"/>
<Setter Property="Padding" Value="14,10"/>
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" />
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="PointerOver" />
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="CheckBox">
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="DatePicker">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Editor">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14" />
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Entry">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14" />
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="ImageButton">
<Setter Property="Opacity" Value="1" />
<Setter Property="BorderColor" Value="Transparent"/>
<Setter Property="BorderWidth" Value="0"/>
<Setter Property="CornerRadius" Value="0"/>
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="Opacity" Value="0.5" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="PointerOver" />
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Label">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular" />
<Setter Property="FontSize" Value="14" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Label" x:Key="Headline">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource MidnightBlue}, Dark={StaticResource White}}" />
<Setter Property="FontSize" Value="32" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="HorizontalTextAlignment" Value="Center" />
</Style>
<Style TargetType="Label" x:Key="SubHeadline">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource MidnightBlue}, Dark={StaticResource White}}" />
<Setter Property="FontSize" Value="24" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="HorizontalTextAlignment" Value="Center" />
</Style>
<Style TargetType="ListView">
<Setter Property="SeparatorColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
<Setter Property="RefreshControlColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
</Style>
<Style TargetType="Picker">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="TitleColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14" />
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
<Setter Property="TitleColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="ProgressBar">
<Setter Property="ProgressColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="ProgressColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="RadioButton">
<Setter Property="BackgroundColor" Value="Transparent"/>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="RefreshView">
<Setter Property="RefreshColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
</Style>
<Style TargetType="SearchBar">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="PlaceholderColor" Value="{StaticResource Gray500}" />
<Setter Property="CancelButtonColor" Value="{StaticResource Gray500}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular" />
<Setter Property="FontSize" Value="14" />
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="SearchHandler">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="PlaceholderColor" Value="{StaticResource Gray500}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular" />
<Setter Property="FontSize" Value="14" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Shadow">
<Setter Property="Radius" Value="15" />
<Setter Property="Opacity" Value="0.5" />
<Setter Property="Brush" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource White}}" />
<Setter Property="Offset" Value="10,10" />
</Style>
<Style TargetType="Slider">
<Setter Property="MinimumTrackColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="MaximumTrackColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray600}}" />
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="MinimumTrackColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}"/>
<Setter Property="MaximumTrackColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}"/>
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="SwipeItem">
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
</Style>
<Style TargetType="Switch">
<Setter Property="OnColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="ThumbColor" Value="{StaticResource White}" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="OnColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="On">
<VisualState.Setters>
<Setter Property="OnColor" Value="{AppThemeBinding Light={StaticResource Secondary}, Dark={StaticResource Gray200}}" />
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Off">
<VisualState.Setters>
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Gray400}, Dark={StaticResource Gray500}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="TimePicker">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="BackgroundColor" Value="Transparent"/>
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<!--
<Style TargetType="TitleBar">
<Setter Property="MinimumHeightRequest" Value="32"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="TitleActiveStates">
<VisualState x:Name="TitleBarTitleActive">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="ForegroundColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="TitleBarTitleInactive">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
<Setter Property="ForegroundColor" Value="{AppThemeBinding Light={StaticResource Gray400}, Dark={StaticResource Gray500}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
-->
<Style TargetType="Page" ApplyToDerivedTypes="True">
<Setter Property="Padding" Value="0"/>
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource OffBlack}}" />
</Style>
<Style TargetType="Shell" ApplyToDerivedTypes="True">
<Setter Property="Shell.BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource OffBlack}}" />
<Setter Property="Shell.ForegroundColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource SecondaryDarkText}}" />
<Setter Property="Shell.TitleColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource SecondaryDarkText}}" />
<Setter Property="Shell.DisabledColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray950}}" />
<Setter Property="Shell.UnselectedColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray200}}" />
<Setter Property="Shell.NavBarHasShadow" Value="False" />
<Setter Property="Shell.TabBarBackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
<Setter Property="Shell.TabBarForegroundColor" Value="{AppThemeBinding Light={StaticResource Magenta}, Dark={StaticResource White}}" />
<Setter Property="Shell.TabBarTitleColor" Value="{AppThemeBinding Light={StaticResource Magenta}, Dark={StaticResource White}}" />
<Setter Property="Shell.TabBarUnselectedColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
</Style>
<Style TargetType="NavigationPage">
<Setter Property="BarBackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource OffBlack}}" />
<Setter Property="BarTextColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource White}}" />
<Setter Property="IconColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource White}}" />
</Style>
<Style TargetType="TabbedPage">
<Setter Property="BarBackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Gray950}}" />
<Setter Property="BarTextColor" Value="{AppThemeBinding Light={StaticResource Magenta}, Dark={StaticResource White}}" />
<Setter Property="UnselectedTabColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray950}}" />
<Setter Property="SelectedTabColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" />
</Style>
</ResourceDictionary>