From d41968117260449ebb8e5371350be52f582b4ebd Mon Sep 17 00:00:00 2001 From: Ange-Marie MAURIN Date: Thu, 10 Jul 2025 20:20:53 +0200 Subject: [PATCH] Add DTFluxRaceResult Module. A Tab to manage RaceResult with a WebConsole interface --- Resources/DTFluxRaceResult16x16.svg | 41 +++ .../DTFluxRaceResult.Build.cs | 34 +++ .../Private/DTFluxRaceResultModule.cpp | 161 ++++++++++ .../Widget/SDTFluxRaceResultWidget.cpp | 283 ++++++++++++++++++ .../Widget/Style/DTFluxRaceResultStyle.cpp | 47 +++ .../Public/DTFluxRaceResultModule.h | 33 ++ .../Public/Widget/SDTFluxRaceResultWidget.h | 54 ++++ .../Widget/Style/DTFluxRaceResultStyle.h | 34 +++ 8 files changed, 687 insertions(+) create mode 100644 Resources/DTFluxRaceResult16x16.svg create mode 100644 Source/DTFluxRaceResult/DTFluxRaceResult.Build.cs create mode 100644 Source/DTFluxRaceResult/Private/DTFluxRaceResultModule.cpp create mode 100644 Source/DTFluxRaceResult/Private/Widget/SDTFluxRaceResultWidget.cpp create mode 100644 Source/DTFluxRaceResult/Private/Widget/Style/DTFluxRaceResultStyle.cpp create mode 100644 Source/DTFluxRaceResult/Public/DTFluxRaceResultModule.h create mode 100644 Source/DTFluxRaceResult/Public/Widget/SDTFluxRaceResultWidget.h create mode 100644 Source/DTFluxRaceResult/Public/Widget/Style/DTFluxRaceResultStyle.h diff --git a/Resources/DTFluxRaceResult16x16.svg b/Resources/DTFluxRaceResult16x16.svg new file mode 100644 index 0000000..66659fe --- /dev/null +++ b/Resources/DTFluxRaceResult16x16.svg @@ -0,0 +1,41 @@ + + + + diff --git a/Source/DTFluxRaceResult/DTFluxRaceResult.Build.cs b/Source/DTFluxRaceResult/DTFluxRaceResult.Build.cs new file mode 100644 index 0000000..1b3f118 --- /dev/null +++ b/Source/DTFluxRaceResult/DTFluxRaceResult.Build.cs @@ -0,0 +1,34 @@ +using UnrealBuildTool; + +public class DTFluxRaceResult : ModuleRules +{ + public DTFluxRaceResult(ReadOnlyTargetRules Target) : base(Target) + { + PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; + + PublicDependencyModuleNames.AddRange( + new string[] + { + "Core" + } + ); + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "CoreUObject", + "Engine", + "Slate", + "SlateCore", + "DTFluxProjectSettings", + "UMG", + "WebBrowser", + "Projects", + "ToolMenus", + "HTTP", + "JsonUtilities", + "Json" + } + ); + } +} \ No newline at end of file diff --git a/Source/DTFluxRaceResult/Private/DTFluxRaceResultModule.cpp b/Source/DTFluxRaceResult/Private/DTFluxRaceResultModule.cpp new file mode 100644 index 0000000..f9d99a0 --- /dev/null +++ b/Source/DTFluxRaceResult/Private/DTFluxRaceResultModule.cpp @@ -0,0 +1,161 @@ +#include "DTFluxRaceResultModule.h" + +#include "LevelEditor.h" +#include "Widget/SDTFluxRaceResultWidget.h" +#include "Widget/Style/DTFluxRaceResultStyle.h" + +#define LOCTEXT_NAMESPACE "FDTFluxRaceResultModule" + +DEFINE_LOG_CATEGORY(logDTFluxRaceResult) + +FName DTFLUXRACERESULT_API FDTFluxRaceResult::RaceResultTabId = "DTFluxRaceResult"; +FText DTFLUXRACERESULT_API FDTFluxRaceResult::RaceResultTabDisplayName = FText::FromString(TEXT("DTFlux RaceResult")); + + +void DTFLUXRACERESULT_API FDTFluxRaceResult::StartupModule() +{ + UE_LOG(logDTFluxRaceResult, Warning, TEXT("DTFluxRaceResult Module Started")) + FDTFluxRaceResultStyle::RegisterStyle(); + InitMenuExtension(); + RegisterRaceResultTab(); +} + +#pragma region MenuExtension + + +void DTFLUXRACERESULT_API FDTFluxRaceResult::InitMenuExtension() +{ + UToolMenus::RegisterStartupCallback( + FSimpleMulticastDelegate::FDelegate::CreateRaw(this, + &FDTFluxRaceResult::RegisterMenuExtensions)); +} + + +void DTFLUXRACERESULT_API FDTFluxRaceResult::RegisterMenuExtensions() +{ + + // Étendre le menu enregistré + if (UToolMenu* DTFluxMenu = UToolMenus::Get()->ExtendMenu("DTFlux.MainMenu")) + { + FToolMenuSection& ToolsSection = DTFluxMenu->FindOrAddSection("Tools"); + ToolsSection.AddMenuEntry( + "DTFluxRaceResult", + FText::FromString("RaceResult"), + FText::FromString("Launch DTFlux RaceResult Control Panel"), + FSlateIcon(FDTFluxRaceResultStyle::GetStyleSetName(), "LevelEditor.Tab.IconRaceResult"), + FUIAction(FExecuteAction::CreateRaw(this, &FDTFluxRaceResult::OnButtonClicked)) + ); + } + +} + +void FDTFluxRaceResult::CreateSubmenu(UToolMenu* Menu) +{ + // Section 2 : Tools + FToolMenuSection& ToolsSection = Menu->FindOrAddSection("Tools"); + ToolsSection.Label = FText::FromString("Tools"); + ToolsSection.AddMenuEntry( + "DTFluxRaceResult", + FText::FromString("RaceResult"), + FText::FromString("Launch Race Result WebAdmin Console"), + FSlateIcon(FDTFluxRaceResultStyle::GetStyleSetName(), "LevelEditor.Tab.IconRaceResult"), + // Adaptez selon votre icône + FUIAction(FExecuteAction::CreateRaw(this, &FDTFluxRaceResult::OnButtonClicked)) + ); +} + +void DTFLUXRACERESULT_API FDTFluxRaceResult::OnButtonClicked() +{ + FGlobalTabmanager::Get()->TryInvokeTab(RaceResultTabId); + UE_LOG(LogTemp, Log, TEXT("Race Result Launched")) +} + +#pragma endregion EditorTab + +#pragma region +void DTFLUXRACERESULT_API FDTFluxRaceResult::RegisterRaceResultTab() +{ + FTabSpawnerEntry& SpawnerEntry = + FGlobalTabmanager::Get()->RegisterNomadTabSpawner( + RaceResultTabId, + FOnSpawnTab::CreateRaw(this, &FDTFluxRaceResult::OnSpawnTab) + ) + .SetDisplayName(RaceResultTabDisplayName) + .SetTooltipText(FText::FromString(TEXT("Race Result Control Panel"))); +} + +TSharedRef DTFLUXRACERESULT_API FDTFluxRaceResult::OnSpawnTab(const FSpawnTabArgs& SpawnTabArgs) +{ + return + SNew( + SDockTab + ) + .TabRole(ETabRole::NomadTab) + // .ShouldAutosize(true) + [ + SNew(SDTFluxRaceResultWidget) + ]; +} + +#pragma endregion +void DTFLUXRACERESULT_API FDTFluxRaceResult::ShutdownModule() +{ + FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(RaceResultTabId); + FDTFluxRaceResultStyle::UnregisterStyle(); +} + + +// +// // Dans votre code de debug +// void DTFLUXRACERESULT_API FDTFluxRaceResult::DebugMenus() +// { +// UToolMenus* ToolMenus = UToolMenus::Get(); +// if (ToolMenus) +// { +// TArray MenuNames; +// ToolMenus->GetAllMenuNames(MenuNames); +// +// UE_LOG(logDTFluxRaceResult, Warning, TEXT("=== ALL AVAILABLE MENUS ===")); +// for (const FName& MenuName : MenuNames) +// { +// UE_LOG(logDTFluxRaceResult, Warning, TEXT("Menu: %s"), *MenuName.ToString()); +// +// // Obtenir les sections de chaque menu +// UToolMenu* Menu = ToolMenus->FindMenu(MenuName); +// if (Menu) +// { +// for (const FToolMenuSection& Section : Menu->Sections) +// { +// UE_LOG(logDTFluxRaceResult, Warning, TEXT(" Section: %s"), *Section.Name.ToString()); +// } +// } +// } +// UE_LOG(logDTFluxRaceResult, Warning, TEXT("=== END MENU LIST ===")); +// } +// } + + +// void DTFLUXRACERESULT_API FDTFluxRaceResult::AddMenu(FMenuBarBuilder& MenuBarBuilder) +// { +// MenuBarBuilder.AddPullDownMenu( +// FText::FromString("DTFlux"), +// FText::FromString("DTFlux API Tools"), +// FNewMenuDelegate::CreateRaw(this, &FDTFluxRaceResult::FillMenu) +// ); +// } + +// void DTFLUXRACERESULT_API FDTFluxRaceResult::FillMenu(FMenuBuilder& MenuBuilder) +// { +// MenuBuilder.AddMenuEntry( +// FText::FromString("RaceResult ControlPanel"), +// FText::FromString("Launch RaceResult Control Panel"), +// FSlateIcon(FDTFluxRaceResultStyle::GetStyleSetName(), "LevelEditor.Tab.IconRaceResult"), +// FExecuteAction::CreateRaw(this, &FDTFluxRaceResult::OnButtonClicked) +// ); +// MenuBuilder.EndSection(); +// } + + +#undef LOCTEXT_NAMESPACE + +IMPLEMENT_MODULE(FDTFluxRaceResult, DTFluxRaceResult) diff --git a/Source/DTFluxRaceResult/Private/Widget/SDTFluxRaceResultWidget.cpp b/Source/DTFluxRaceResult/Private/Widget/SDTFluxRaceResultWidget.cpp new file mode 100644 index 0000000..e601412 --- /dev/null +++ b/Source/DTFluxRaceResult/Private/Widget/SDTFluxRaceResultWidget.cpp @@ -0,0 +1,283 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Widget/SDTFluxRaceResultWidget.h" + +#include "DTFluxRaceResultModule.h" +#include "HttpModule.h" +#include "IWebBrowserCookieManager.h" +#include "IWebBrowserWindow.h" +#include "SlateOptMacros.h" +#include "WebBrowserModule.h" +#include "Interfaces/IHttpRequest.h" +#include "Interfaces/IHttpResponse.h" + +BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION + +void SDTFluxRaceResultWidget::Construct(const FArguments& InArgs) +{ + + FWebBrowserInitSettings browserInitSettings = FWebBrowserInitSettings(); + + IWebBrowserModule::Get().CustomInitialize(browserInitSettings); + WindowSettings.InitialURL = TEXT("about:blank"); + WindowSettings.BrowserFrameRate = 25; + + if (IWebBrowserModule::IsAvailable() && IWebBrowserModule::Get().IsWebModuleAvailable()) + { + IWebBrowserSingleton* WebBrowserSingleton = IWebBrowserModule::Get().GetSingleton(); + Browser = WebBrowserSingleton->CreateBrowserWindow(WindowSettings); + // Browser->OnLoadUrl().BindRaw(this, &SDTFluxRaceResultWidget::OnLoadOverride); + + } + + + ChildSlot + [ + SNew(SBox) + .Padding(5.0f) + [ + SNew(SBorder) + .BorderImage(FCoreStyle::Get().GetBrush("ToolPanel.GroupBorder")) + [ + SNew(SVerticalBox) + + SVerticalBox::Slot() + [ + SAssignNew(WebBrowser, SWebBrowser, Browser) + .ShowControls(true) + .SupportsTransparency(true) + .OnUrlChanged(this, &SDTFluxRaceResultWidget::OnUrlChanged) + .OnBeforeNavigation(this, &SDTFluxRaceResultWidget::OnBeforeNavigation) + .OnLoadCompleted(FSimpleDelegate::CreateRaw(this, &SDTFluxRaceResultWidget::OnLoadCompleted)) + .OnLoadError(FSimpleDelegate::CreateRaw(this, &SDTFluxRaceResultWidget::OnLoadError)) + .OnLoadStarted(FSimpleDelegate::CreateRaw(this, &SDTFluxRaceResultWidget::OnLoadStarted)) + .ShowErrorMessage(true) + .ShowAddressBar(true) + ] + ] + ] + ]; + +} + +void SDTFluxRaceResultWidget::OnCookieSet(bool bSuccess) +{ +} + + +void SDTFluxRaceResultWidget::LoadContentViaHTTP() +{ + UE_LOG(logDTFluxRaceResult, Log, TEXT("Loading initial content via HTTP: %s"), *RaceResultUrl); + LoadSpecificURL(RaceResultUrl); +} + + +void SDTFluxRaceResultWidget::LoadSpecificURL(const FString& Url) +{ + UE_LOG(logDTFluxRaceResult, Log, TEXT("Loading via HTTP: %s"), *Url); + + // Créer la requête HTTP + TSharedRef Request = FHttpModule::Get().CreateRequest(); + + // Ajouter l'authentification Basic pour TOUTES les requêtes + FString Credentials = Username + TEXT(":") + Password; + FString EncodedCredentials = FBase64::Encode(Credentials); + + Request->SetURL(Url); + Request->SetVerb("GET"); + Request->SetHeader("Authorization", "Basic " + EncodedCredentials); + Request->SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"); + Request->SetHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"); + Request->SetHeader("Accept-Language", "en-US,en;q=0.5"); + Request->SetHeader("Accept-Encoding", "gzip, deflate"); + Request->SetHeader("Connection", "keep-alive"); + + Request->OnProcessRequestComplete().BindRaw(this, &SDTFluxRaceResultWidget::OnHTTPContentLoaded); + Request->ProcessRequest(); + + UE_LOG(logDTFluxRaceResult, Log, TEXT("HTTP request sent with Basic Auth")); +} + +void SDTFluxRaceResultWidget::OnHTTPContentLoaded(TSharedPtr Request, + TSharedPtr HttpResponse, bool bWasSuccessful) +{ + if (bWasSuccessful && HttpResponse.IsValid()) + { + int32 ResponseCode = HttpResponse->GetResponseCode(); + UE_LOG(logDTFluxRaceResult, Log, TEXT("HTTP Response Code: %d"), ResponseCode); + + if (ResponseCode == 200) + { + FString Content = HttpResponse->GetContentAsString(); + UE_LOG(logDTFluxRaceResult, Log, TEXT("Content loaded successfully, size: %d characters"), Content.Len()); + + // Traiter le contenu HTML + FString ProcessedContent = ProcessHTMLContent(Content, Request->GetURL()); + + // Charger le contenu dans le browser via LoadString + if (Browser.IsValid()) + { + Browser->LoadString(ProcessedContent, Request->GetURL()); + UE_LOG(logDTFluxRaceResult, Log, TEXT("Content loaded into browser")); + } + } + else if (ResponseCode == 401) + { + UE_LOG(logDTFluxRaceResult, Error, TEXT("Authentication failed - 401 Unauthorized. Check your credentials.")); + } + else if (ResponseCode == 403) + { + UE_LOG(logDTFluxRaceResult, Error, TEXT("Access forbidden - 403 Forbidden")); + } + else if (ResponseCode == 404) + { + UE_LOG(logDTFluxRaceResult, Error, TEXT("Page not found - 404 Not Found")); + } + else + { + UE_LOG(logDTFluxRaceResult, Error, TEXT("HTTP request failed with code: %d"), ResponseCode); + } + } + else + { + UE_LOG(logDTFluxRaceResult, Error, TEXT("HTTP request failed completely")); + } +} + +void SDTFluxRaceResultWidget::OnLoadOverride() +{ +} + + +void SDTFluxRaceResultWidget::OnUrlChanged(const FText& NewUrl) +{ + UE_LOG(logDTFluxRaceResult, Log, TEXT("URL changed to: %s"), *NewUrl.ToString()); +} + +FString SDTFluxRaceResultWidget::ProcessHTMLContent(const FString& Content, const FString& BaseUrl) +{ + FString ProcessedContent = Content; + + // Extraire le domaine de base + FString BaseDomain = ExtractDomain(BaseUrl); + + UE_LOG(logDTFluxRaceResult, Log, TEXT("Processing HTML content, base domain: %s"), *BaseDomain); + + // Convertir tous les liens relatifs en liens absolus + ProcessedContent = ProcessedContent.Replace(TEXT("src=\"/"), *FString::Printf(TEXT("src=\"%s/"), *BaseDomain)); + ProcessedContent = ProcessedContent.Replace(TEXT("href=\"/"), *FString::Printf(TEXT("href=\"%s/"), *BaseDomain)); + ProcessedContent = ProcessedContent.Replace(TEXT("src='/"), *FString::Printf(TEXT("src='%s/"), *BaseDomain)); + ProcessedContent = ProcessedContent.Replace(TEXT("href='/"), *FString::Printf(TEXT("href='%s/"), *BaseDomain)); + + // Gérer les liens relatifs avec ./ + ProcessedContent = ProcessedContent.Replace(TEXT("src=\"./"), *FString::Printf(TEXT("src=\"%s/"), *BaseDomain)); + ProcessedContent = ProcessedContent.Replace(TEXT("href=\"./"), *FString::Printf(TEXT("href=\"%s/"), *BaseDomain)); + + // Ajouter une balise base pour aider avec les liens relatifs restants + FString BaseTag = FString::Printf(TEXT(""), *BaseDomain); + if (ProcessedContent.Contains(TEXT(""))) + { + FString HeadReplacement = TEXT("") + BaseTag; + ProcessedContent = ProcessedContent.Replace(TEXT(""), *HeadReplacement); + } + else if (ProcessedContent.Contains(TEXT(""))) + { + FString HeadReplacement = TEXT("") + BaseTag; + ProcessedContent = ProcessedContent.Replace(TEXT(""), *HeadReplacement); + } + + UE_LOG(logDTFluxRaceResult, Log, TEXT("HTML content processed")); + return ProcessedContent; +} + + +FString SDTFluxRaceResultWidget::ExtractDomain(const FString& Url) +{ + FString Domain = Url; + + // Enlever le protocole + if (Url.StartsWith(TEXT("https://"))) + { + Domain = Url.Mid(8); + } + else if (Url.StartsWith(TEXT("http://"))) + { + Domain = Url.Mid(7); + } + + // Trouver le premier slash (début du path) + int32 SlashIndex; + if (Domain.FindChar(TEXT('/'), SlashIndex)) + { + Domain = Url.Left(Url.Len() - (Domain.Len() - SlashIndex)); + } + + // Enlever le port si présent + FString DomainPart = Domain; + if (Domain.StartsWith(TEXT("https://"))) + { + DomainPart = Domain.Mid(8); + } + else if (Domain.StartsWith(TEXT("http://"))) + { + DomainPart = Domain.Mid(7); + } + + int32 ColonIndex; + if (DomainPart.FindChar(TEXT(':'), ColonIndex)) + { + Domain = Domain.Left(Domain.Len() - (DomainPart.Len() - ColonIndex)); + } + + return Domain; +} + +bool SDTFluxRaceResultWidget::OnBeforeNavigation(const FString& Url, const FWebNavigationRequest& Request) +{ + + UE_LOG(logDTFluxRaceResult, Log, TEXT("Loading via HTTP: %s"), *Url); + + TSharedRef HTTPRequest = FHttpModule::Get().CreateRequest(); + + // Authentification pour toutes les requêtes + FString Credentials = Username + TEXT(":") + Password; + FString EncodedCredentials = FBase64::Encode(Credentials); + + HTTPRequest->SetURL(RaceResultUrl); + HTTPRequest->SetVerb("GET"); + HTTPRequest->SetHeader("Authorization", "Basic " + EncodedCredentials); + HTTPRequest->SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"); + HTTPRequest->SetHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); + + HTTPRequest->OnProcessRequestComplete().BindRaw(this, &SDTFluxRaceResultWidget::OnHTTPContentLoaded); + HTTPRequest->ProcessRequest(); + + return true; +} + +void SDTFluxRaceResultWidget::OnLoadCompleted() +{ + UE_LOG(logDTFluxRaceResult, Log, TEXT("Load Completed")); + +} + +void SDTFluxRaceResultWidget::OnLoadStarted() +{ + UE_LOG(logDTFluxRaceResult, Log, TEXT("Load Started")); +} + +void SDTFluxRaceResultWidget::OnLoadError() +{ + UE_LOG(logDTFluxRaceResult, Log, TEXT("Load Error")); +} + +void SDTFluxRaceResultWidget::OnBeforeResourceLoad(FString Url, FString ResourceType, FContextRequestHeaders& AdditionalHeaders, const bool AllowUserCredentials) +{ +} + +void SDTFluxRaceResultWidget::SetupBasicAuth() +{ + +} + +END_SLATE_FUNCTION_BUILD_OPTIMIZATION diff --git a/Source/DTFluxRaceResult/Private/Widget/Style/DTFluxRaceResultStyle.cpp b/Source/DTFluxRaceResult/Private/Widget/Style/DTFluxRaceResultStyle.cpp new file mode 100644 index 0000000..bb36f95 --- /dev/null +++ b/Source/DTFluxRaceResult/Private/Widget/Style/DTFluxRaceResultStyle.cpp @@ -0,0 +1,47 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Widget/Style/DTFluxRaceResultStyle.h" + + +#include "Interfaces/IPluginManager.h" +#include "Styling/SlateStyleRegistry.h" +#include "Styling/SlateStyleMacros.h" + +#define RootToContentDir Style->RootToContentDir + +TSharedPtr FDTFluxRaceResultStyle::StyleSet = nullptr; + +void FDTFluxRaceResultStyle::RegisterStyle() +{ + if(StyleSet.IsValid()) return; + + StyleSet = Create(); + FSlateStyleRegistry::RegisterSlateStyle(*StyleSet); +} + +void FDTFluxRaceResultStyle::UnregisterStyle() +{ + if(StyleSet.IsValid()) + { + FSlateStyleRegistry::UnRegisterSlateStyle(*StyleSet); + ensure(StyleSet.IsUnique()); + StyleSet.Reset(); + } + + +} + +void FDTFluxRaceResultStyle::ReloadTextures() +{ +} + +TSharedPtr FDTFluxRaceResultStyle::Create() +{ + TSharedPtr Style = MakeShareable(new FSlateStyleSet("DTFluxRaceResultStyle")); + Style->SetContentRoot(IPluginManager::Get().FindPlugin("DTFluxAPI")->GetBaseDir()/TEXT("Resources")); + + Style->Set("LevelEditor.Tab.IconRaceResult", new IMAGE_BRUSH_SVG("DTFluxRaceResult16x16", FVector2d(16)) ); + return Style; +} + diff --git a/Source/DTFluxRaceResult/Public/DTFluxRaceResultModule.h b/Source/DTFluxRaceResult/Public/DTFluxRaceResultModule.h new file mode 100644 index 0000000..444a717 --- /dev/null +++ b/Source/DTFluxRaceResult/Public/DTFluxRaceResultModule.h @@ -0,0 +1,33 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Modules/ModuleManager.h" + +DTFLUXRACERESULT_API DECLARE_LOG_CATEGORY_EXTERN(logDTFluxRaceResult, All, All); + +class DTFLUXRACERESULT_API FDTFluxRaceResult : public IModuleInterface +{ +public: + virtual void StartupModule() override; + virtual void ShutdownModule() override; + +#pragma region MenuExtention + void RegisterMenuExtensions(); + void InitMenuExtension(); + void CreateSubmenu(UToolMenu* Menu); + + // void AddMenu(FMenuBarBuilder& MenuBarBuilder); + // void FillMenu(FMenuBuilder& MenuBuilder); + void OnButtonClicked(); +#pragma endregion + +#pragma region EditorTab + void RegisterRaceResultTab(); + TSharedRef OnSpawnTab(const FSpawnTabArgs& SpawnTabArgs); +private: + // static void DebugMenus(); + static FName RaceResultTabId; + static FText RaceResultTabDisplayName; + TSharedPtr RaceResultWidget; +#pragma endregion +}; diff --git a/Source/DTFluxRaceResult/Public/Widget/SDTFluxRaceResultWidget.h b/Source/DTFluxRaceResult/Public/Widget/SDTFluxRaceResultWidget.h new file mode 100644 index 0000000..25bc2f0 --- /dev/null +++ b/Source/DTFluxRaceResult/Public/Widget/SDTFluxRaceResultWidget.h @@ -0,0 +1,54 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "SWebBrowser.h" +#include "Widgets/SCompoundWidget.h" + +class IHttpResponse; +class IHttpRequest; +/** + * + */ +class DTFLUXRACERESULT_API SDTFluxRaceResultWidget : public SCompoundWidget +{ +public: + SLATE_BEGIN_ARGS(SDTFluxRaceResultWidget) + { + } + + SLATE_END_ARGS() + + /** Constructs this widget with InArgs */ + void Construct(const FArguments& InArgs); + void OnCookieSet(bool bSuccess); + void LoadSpecificURL(const FString& Url); + void LoadContentViaHTTP(); + +private: + TSharedPtr WebBrowser; + TSharedPtr Browser; + TSharedPtr BrowserAdapter; + FCreateBrowserWindowSettings WindowSettings; + + void OnUrlChanged(const FText& NewUrl); + FString ProcessHTMLContent(const FString& Content, const FString& BaseUrl); + FString ExtractDomain(const FString& Url); + void OnHTTPContentLoaded(TSharedPtr Request, TSharedPtr HttpResponse, bool bWasSuccessful); + bool OnBeforeNavigation(const FString& Url, const FWebNavigationRequest& Request); + void OnLoadCompleted(); + void OnLoadStarted(); + void OnLoadError(); + + void OnLoadOverride(); + + void OnBeforeResourceLoad(FString Url, FString ResourceType, FContextRequestHeaders& AdditionalHeaders, const bool AllowUserCredentials); + + FString RaceResultUrl = "https://raceresult.tds-france.com"; + FString Username = "sporkrono"; + FString Password = "Notre 3ème décennie d'action pour le climat"; + + + void SetupBasicAuth(); +}; diff --git a/Source/DTFluxRaceResult/Public/Widget/Style/DTFluxRaceResultStyle.h b/Source/DTFluxRaceResult/Public/Widget/Style/DTFluxRaceResultStyle.h new file mode 100644 index 0000000..ad9fc1e --- /dev/null +++ b/Source/DTFluxRaceResult/Public/Widget/Style/DTFluxRaceResultStyle.h @@ -0,0 +1,34 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Styling/ISlateStyle.h" + + +/** + * + */ +class DTFLUXRACERESULT_API FDTFluxRaceResultStyle +{ + +public: + static void RegisterStyle(); + static void UnregisterStyle(); + + static void ReloadTextures(); + + static const ISlateStyle& Get() + { + return *StyleSet; + } + + static const FName& GetStyleSetName() + { + return StyleSet->GetStyleSetName(); + } + +private: + static TSharedPtr Create(); + static TSharedPtr StyleSet; +};