Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert ChartFox interfacing to v2 API. #204

Merged
merged 1 commit into from
May 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,18 @@
*.app

# Project specific ignores
build
build-third
cmake-build-debug
/build/
/build-third/
/cmake-build-debug/
/build-*/
/scratch/

# Ignore hidden files, apart from some project specifics
/.*
!/.gitattributes
!/.gitignore
!/.gitmodules
!/.clang-format

# Jetbrains IDE
.idea/
Expand All @@ -46,6 +55,7 @@ cmake-build-debug

# VSCode IDE
.vscode/
*.code-workspace

# clangd index and compilation database
.cache
Expand Down
6 changes: 3 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
cmake_minimum_required(VERSION 3.9)
cmake_minimum_required(VERSION 3.20)
project(AviTab VERSION 0.6.3 DESCRIPTION "AviTab X-Plane plugin")

if (NOT "$ENV{NAVIGRAPH_SECRET}" STREQUAL "")
set(NAVIGRAPH_SECRET "$ENV{NAVIGRAPH_SECRET}" CACHE INTERNAL "Copied from environment variable")
endif()
if (NOT "$ENV{CHARTFOX_SECRET}" STREQUAL "")
set(CHARTFOX_SECRET "$ENV{CHARTFOX_SECRET}" CACHE INTERNAL "Copied from environment variable")
if (NOT "$ENV{CHARTFOX_CLIENTID}" STREQUAL "")
set(CHARTFOX_CLIENTID "$ENV{CHARTFOX_CLIENTID}" CACHE INTERNAL "Copied from environment variable")
endif()

configure_file(
Expand Down
2 changes: 1 addition & 1 deletion config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@
#define AVITAB_VERSION_PATCH @AviTab_VERSION_PATCH@
#define AVITAB_VERSION_STR "@AviTab_VERSION_MAJOR@.@AviTab_VERSION_MINOR@.@AviTab_VERSION_PATCH@"
#define NAVIGRAPH_CLIENT_SECRET "@NAVIGRAPH_SECRET@"
#define CHARTFOX_CLIENT_SECRET "@CHARTFOX_SECRET@"
#define CHARTFOX_CLIENT_ID "@CHARTFOX_CLIENTID@"
5 changes: 3 additions & 2 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,9 @@ if(WIN32 AND DEFINED ENV{MSFS_SDK})
)

add_library(SimConnect STATIC IMPORTED)
set_property(TARGET SimConnect PROPERTY IMPORTED_LOCATION "$ENV{MSFS_SDK}/SimConnect SDK/lib/SimConnect.dll")
set_property(TARGET SimConnect PROPERTY IMPORTED_IMPLIB "$ENV{MSFS_SDK}/SimConnect SDK/lib/SimConnect.lib")
cmake_path(SET MSFS_SDK $ENV{MSFS_SDK})
set_property(TARGET SimConnect PROPERTY IMPORTED_LOCATION "${MSFS_SDK}/SimConnect SDK/lib/SimConnect.dll")
set_property(TARGET SimConnect PROPERTY IMPORTED_IMPLIB "${MSFS_SDK}/SimConnect SDK/lib/SimConnect.lib")

target_link_libraries(AviTab-msfs
-static
Expand Down
2 changes: 1 addition & 1 deletion src/avitab/apps/AppLauncher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ AppLauncher::AppLauncher(FuncsPtr appFuncs):
addEntry<PlaneManualApp>("Aircraft", root + "if_ilustracoes_04-11_1519786.png", AppId::PLANE_MANUAL);
addEntry<NotesApp>("Notes", root + "if_txt2_3783.png", AppId::NOTES);

if (api().getChartService()->getNavigraph()->isSupported() || api().getChartService()->getChartfox()->isSupported()) {
if (api().getChartService()->getNavigraph()->isSupported() || api().getChartService()->getChartFox()->isSupported()) {
addEntry<ProvidersApp>("Providers", root + "if_Airport_22906.png", AppId::NAVIGRAPH);
}

Expand Down
179 changes: 135 additions & 44 deletions src/avitab/apps/ProvidersApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,17 @@ ProvidersApp::ProvidersApp(FuncsPtr appFuncs):
}
}

if (api().getChartService()->getChartfox()->isSupported()) {
if (api().getChartService()->getChartFox() != nullptr) {
chartFoxPage = tabs->addTab(tabs, "ChartFox");
windowChartFox = std::make_shared<Window>(chartFoxPage, "ChartFox");
windowChartFox->setOnClose([this] () { exit(); });
resetChartFoxLayout();

auto chartFox = api().getChartService()->getChartFox();
if (chartFox->isAuthenticated()) {
// modify the tab to display as if just logged in
onChartFoxLoginSuccessful();
}
}
}

Expand All @@ -60,27 +66,27 @@ void ProvidersApp::resetNavigraphLayout() {
labelNavigraph->setLongMode(true);
labelNavigraph->alignInTopLeft();

button.reset();
button = std::make_shared<Button>(windowNavigraph, "Link Navigraph Account");
button->alignBelow(labelNavigraph);
button->setCallback([this] (const Button &btn) {
linkNavigraphButton.reset();
linkNavigraphButton = std::make_shared<Button>(windowNavigraph, "Link Navigraph Account");
linkNavigraphButton->alignBelow(labelNavigraph);
linkNavigraphButton->setCallback([this] (const Button &btn) {
api().executeLater([this] () { onNavigraphLogin(); });
});
}

void ProvidersApp::onNavigraphLogin() {
auto svc = api().getChartService();

button.reset();
linkNavigraphButton.reset();
labelNavigraph->setText("Logging in...");

auto call = svc->loginNavigraph();
call->andThen([this] (std::future<bool> result) {
try {
result.get();
api().executeLater([this] () { onAuthSuccess(); });
api().executeLater([this] () { onNavigraphAuthSuccess(); });
} catch (const navigraph::LoginException &e) {
api().executeLater([this] () { onAuthRequired(); });
api().executeLater([this] () { onNavigraphAuthRequired(); });
} catch (const std::exception &e) {
labelNavigraph->setTextFormatted("Error: %s", e.what());
}
Expand All @@ -89,23 +95,23 @@ void ProvidersApp::onNavigraphLogin() {
svc->submitCall(call);
}

void ProvidersApp::onAuthRequired() {
void ProvidersApp::onNavigraphAuthRequired() {
auto navigraph = api().getChartService()->getNavigraph();

labelNavigraph->setText("Linking required\n"
"Clicking the button will open your browser to login to your Navigraph account.\n"
"Clicking the linkNavigraphButton will open your browser to login to your Navigraph account.\n"
"If your browser doesn't start, you can find the link to open in AviTab.log\n"
"This process is required only once every 30 days.");

button.reset();
button = std::make_shared<Button>(windowNavigraph, "Open Browser");
button->alignBelow(labelNavigraph);
button->setCallback([this] (const Button &) {
api().executeLater([this] () { onStartAuth(); });
linkNavigraphButton.reset();
linkNavigraphButton = std::make_shared<Button>(windowNavigraph, "Open Browser");
linkNavigraphButton->alignBelow(labelNavigraph);
linkNavigraphButton->setCallback([this] (const Button &) {
api().executeLater([this] () { onNavigraphStartAuth(); });
});
}

void ProvidersApp::onStartAuth() {
void ProvidersApp::onNavigraphStartAuth() {
auto navigraph = api().getChartService()->getNavigraph();
auto link = navigraph->startAuthentication([this] {
api().executeLater([this] () {
Expand All @@ -118,73 +124,71 @@ void ProvidersApp::onStartAuth() {
labelNavigraph->setText("Follow the instructions in your browser.\n"
"If your browser didn't start, manually open the link in AviTab's log file");

button = std::make_shared<Button>(windowNavigraph, "Cancel");
button->alignBelow(labelNavigraph);
button->setCallback([this] (const Button &btn) {
api().executeLater([this] () { onCancelLoginButton(); });
linkNavigraphButton = std::make_shared<Button>(windowNavigraph, "Cancel");
linkNavigraphButton->alignBelow(labelNavigraph);
linkNavigraphButton->setCallback([this] (const Button &btn) {
api().executeLater([this] () { onNavigraphCancelLoginButton(); });
});
}

void ProvidersApp::onCancelLoginButton() {
void ProvidersApp::onNavigraphCancelLoginButton() {
auto navigraph = api().getChartService()->getNavigraph();
navigraph->cancelAuth();
resetNavigraphLayout();
}

void ProvidersApp::onAuthSuccess() {
void ProvidersApp::onNavigraphAuthSuccess() {
auto navigraph = api().getChartService()->getNavigraph();
if (navigraph->isInDemoMode()) {
labelNavigraph->setText("Your Navigraph account is linked but doesn't have a charts subscription.\n"
"Only LEAL and KONT are usable in demo mode.\n"
"Visit navigraph.com to subscribe to Navigraph Charts or Ultimate.\n"
"Use the Airport app to access the demo charts.\n"
"Use the home button or the X to close this app.\n");
"Use the home linkNavigraphButton or the X to close this app.\n");
} else {
labelNavigraph->setText("Your Navigraph account is now linked to AviTab! Use the Airport app to access charts.\n"
"Use the home button or the X to close this app.\n");
"Use the home linkNavigraphButton or the X to close this app.\n");
}

button.reset();
button = std::make_shared<Button>(windowNavigraph, "Switch Account");
button->alignBelow(labelNavigraph);
button->setCallback([this] (const Button &btn) {
api().executeLater([this] () { onLogoutButton(); });
linkNavigraphButton.reset();
linkNavigraphButton = std::make_shared<Button>(windowNavigraph, "Switch Account");
linkNavigraphButton->alignBelow(labelNavigraph);
linkNavigraphButton->setCallback([this] (const Button &btn) {
api().executeLater([this] () { onNavigraphLogoutButton(); });
});
}

void ProvidersApp::onLogoutButton() {
void ProvidersApp::onNavigraphLogoutButton() {
auto navigraph = api().getChartService()->getNavigraph();
navigraph->logout();
resetNavigraphLayout();
}

void ProvidersApp::resetChartFoxLayout() {
api().getChartService()->setUseChartFox(false);

labelChartFox.reset();
labelChartFox = std::make_shared<Label>(windowChartFox,
"ChartFox.org is a free online service that collects the web locations of\n"
"chartfox.org is a free online service that collects the web locations of\n"
"several official and unofficial (e.g. Vatsim) charts.\n"
"AviTab can use ChartFox to look up the locations of airport charts\n"
"AviTab can use your ChartFox account to look up the locations of airport charts\n"
"in order to download them from 3rd party sites for you.\n"
"\n"
"If you want to donate to ChartFox, use the button below (opens browser).\n"
"Click the Link Account button to authorise Avitab to use your ChartFox account.\n"
"If you want to donate to ChartFox, use the Donate below (opens browser).\n"
);
labelChartFox->setLongMode(true);
labelChartFox->alignInTopLeft();

chartFoxCheckbox = std::make_shared<Checkbox>(windowChartFox, "Use ChartFox in airport app");
chartFoxCheckbox->alignBelow(labelChartFox);

bool useCf = api().getSettings()->getGeneralSetting<bool>("useChartFox");
api().getChartService()->setUseChartFox(useCf);

chartFoxCheckbox->setChecked(useCf);
chartFoxCheckbox->setCallback([this] (bool checked) {
api().getSettings()->setGeneralSetting("useChartFox", checked);
api().getChartService()->setUseChartFox(checked);
chartFoxActionButton.reset();
chartFoxActionButton = std::make_shared<Button>(windowChartFox, "Link Account");
chartFoxActionButton->alignBelow(labelChartFox);
chartFoxActionButton->setCallback([this] (const Button &btn) {
api().executeLater([this] () { testChartFoxLinkage(); });
});

chartFoxDonateButton = std::make_shared<Button>(windowChartFox, "Donate to ChartFox");
chartFoxDonateButton->alignBelow(chartFoxCheckbox);
chartFoxDonateButton->alignInBottomRight();
chartFoxDonateButton->setCallback([this] (const Button &) {
auto call = api().getChartService()->getChartFoxDonationLink();
call->andThen([] (std::future<std::string> urlFuture) {
Expand All @@ -199,4 +203,91 @@ void ProvidersApp::resetChartFoxLayout() {
});
}

void ProvidersApp::testChartFoxLinkage() {
auto svc = api().getChartService();

// short (transient) message, and no button
labelChartFox->setText("Logging in...");
chartFoxActionButton.reset();

auto call = svc->verifyChartFoxAccess();
call->andThen([this] (std::future<bool> result) {
try {
bool authenticated = result.get();
if (!authenticated) throw chartfox::LoginException();
api().executeLater([this] () { onChartFoxLoginSuccessful(); });
} catch (const chartfox::LoginException &e) {
api().executeLater([this] () { onChartFoxAuthRequired(); });
} catch (const std::exception &e) {
labelChartFox->setTextFormatted("Error: %s", e.what());
}
});

svc->submitCall(call);
}

void ProvidersApp::onChartFoxAuthRequired() {
api().getChartService()->setUseChartFox(false);

labelChartFox->setText("ChartFox login is required.\n"
"Clicking Open Browser will open your browser to login to your ChartFox account.\n"
"If your browser doesn't start, you can find the URL to visit in AviTab.log\n");

chartFoxActionButton.reset();
chartFoxActionButton = std::make_shared<Button>(windowChartFox, "Open Browser");
chartFoxActionButton->alignBelow(labelChartFox);
chartFoxActionButton->setCallback([this] (const Button &) {
api().executeLater([this] () { onChartFoxStartAuth(); });
});
}

void ProvidersApp::onChartFoxStartAuth() {
auto chartFox = api().getChartService()->getChartFox();
if (chartFox == nullptr) return;
auto link = chartFox->startAuthentication([this] {
api().executeLater([this] () {
testChartFoxLinkage(); // callback on completion of the OAuth(PKCE) flow
});
});

platform::openBrowser(link);
labelChartFox->setText("Follow the instructions in your browser.\n"
"If your browser didn't start, visit the URL manually.\n"
"The URL can be found in AviTab's log file, near the end.");

chartFoxActionButton = std::make_shared<Button>(windowChartFox, "Cancel");
chartFoxActionButton->alignBelow(labelChartFox);
chartFoxActionButton->setCallback([this] (const Button &btn) {
api().executeLater([this] () { onChartFoxCancelLoginButton(); });
});
}

void ProvidersApp::onChartFoxCancelLoginButton() {
auto chartFox = api().getChartService()->getChartFox();
if (chartFox) chartFox->cancelAuth();
resetChartFoxLayout();
}

void ProvidersApp::onChartFoxLoginSuccessful() {
labelChartFox->setText("Avitab is authorised to use your ChartFox account and will\n"
"attempt to download charts indexed by ChartFox when you use\n"
"the Airport app. You can revoke this by clicking Logout.\n"
"Use the home button or the X to close this app.\n");

chartFoxActionButton.reset();
chartFoxActionButton = std::make_shared<Button>(windowChartFox, "Logout");
chartFoxActionButton->alignBelow(labelChartFox);
chartFoxActionButton->setCallback([this] (const Button &btn) {
api().executeLater([this] () { onChartFoxLogoutButton(); });
});

api().getChartService()->setUseChartFox(true);
}

void ProvidersApp::onChartFoxLogoutButton() {
auto chartFox = api().getChartService()->getChartFox();
if (chartFox) chartFox->logout();
resetChartFoxLayout();
}

} /* namespace avitab */
26 changes: 14 additions & 12 deletions src/avitab/apps/ProvidersApp.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef SRC_AVITAB_APPS_PROVIDERSAPP_H_
#define SRC_AVITAB_APPS_PROVIDERSAPP_H_
#pragma once

#include <memory>
#include "App.h"
Expand All @@ -36,24 +35,27 @@ class ProvidersApp: public App {
std::shared_ptr<TabGroup> tabs;
std::shared_ptr<Window> windowNavigraph, windowChartFox;
std::shared_ptr<Label> labelNavigraph, labelChartFox;
std::shared_ptr<Button> button;
std::shared_ptr<PixMap> pixmap;
std::shared_ptr<Button> linkNavigraphButton, chartFoxActionButton;

std::shared_ptr<Page> navigraphPage, chartFoxPage;
std::shared_ptr<Checkbox> chartFoxCheckbox;
std::shared_ptr<Button> chartFoxDonateButton;

void resetNavigraphLayout();
void onNavigraphLogin();
void onAuthRequired();
void onStartAuth();
void onCancelLoginButton();
void onAuthSuccess();
void onLogoutButton();
void onNavigraphAuthRequired();
void onNavigraphStartAuth();
void onNavigraphCancelLoginButton();
void onNavigraphAuthSuccess();
void onNavigraphLogoutButton();

void resetChartFoxLayout();
void testChartFoxLinkage();
void onChartFoxAuthComplete();
void onChartFoxAuthRequired();
void onChartFoxStartAuth();
void onChartFoxCancelLoginButton();
void onChartFoxLoginSuccessful();
void onChartFoxLogoutButton();
};

} /* namespace avitab */

#endif /* SRC_AVITAB_APPS_PROVIDERSAPP_H_ */
Loading