fit-webview-bridge 0.2.3a2__tar.gz → 0.2.4a1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of fit-webview-bridge might be problematic. Click here for more details.
- {fit_webview_bridge-0.2.3a2 → fit_webview_bridge-0.2.4a1}/PKG-INFO +1 -1
- {fit_webview_bridge-0.2.3a2 → fit_webview_bridge-0.2.4a1}/pyproject.toml +1 -1
- {fit_webview_bridge-0.2.3a2 → fit_webview_bridge-0.2.4a1}/src/macos/WKWebViewWidget.h +2 -0
- {fit_webview_bridge-0.2.3a2 → fit_webview_bridge-0.2.4a1}/src/macos/WKWebViewWidget.mm +128 -1
- {fit_webview_bridge-0.2.3a2 → fit_webview_bridge-0.2.4a1}/.github/workflows/wheels-macos.yml +0 -0
- {fit_webview_bridge-0.2.3a2 → fit_webview_bridge-0.2.4a1}/.gitignore +0 -0
- {fit_webview_bridge-0.2.3a2 → fit_webview_bridge-0.2.4a1}/.vscode/settings.json +0 -0
- {fit_webview_bridge-0.2.3a2 → fit_webview_bridge-0.2.4a1}/CMakeLists.txt +0 -0
- {fit_webview_bridge-0.2.3a2 → fit_webview_bridge-0.2.4a1}/README.md +0 -0
- {fit_webview_bridge-0.2.3a2 → fit_webview_bridge-0.2.4a1}/bindings/pyside6/macos/CMakeLists.txt +0 -0
- {fit_webview_bridge-0.2.3a2 → fit_webview_bridge-0.2.4a1}/bindings/pyside6/macos/typesystem_wkwebview.xml +0 -0
- {fit_webview_bridge-0.2.3a2 → fit_webview_bridge-0.2.4a1}/examples/macos/wkwebview_demo.py +0 -0
- {fit_webview_bridge-0.2.3a2 → fit_webview_bridge-0.2.4a1}/fit_webview_bridge/__init__.py +0 -0
- {fit_webview_bridge-0.2.3a2 → fit_webview_bridge-0.2.4a1}/src/macos/CMakeLists.txt +0 -0
- {fit_webview_bridge-0.2.3a2 → fit_webview_bridge-0.2.4a1}/src/macos/DownloadInfo.h +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "fit-webview-bridge"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.4a1"
|
|
4
4
|
description = "Qt native WebView bridge with PySide6 bindings"
|
|
5
5
|
requires-python = ">=3.11,<3.14"
|
|
6
6
|
dependencies = ["PySide6==6.9.0", "shiboken6==6.9.0", "shiboken6-generator==6.9.0"]
|
|
@@ -26,6 +26,7 @@ public:
|
|
|
26
26
|
|
|
27
27
|
Q_INVOKABLE void setDownloadDirectory(const QString& dirPath);
|
|
28
28
|
Q_INVOKABLE QString downloadDirectory() const;
|
|
29
|
+
void renderErrorPage(const QUrl& url, const QString& reason, int httpStatus);
|
|
29
30
|
|
|
30
31
|
signals:
|
|
31
32
|
void loadFinished(bool ok);
|
|
@@ -34,6 +35,7 @@ signals:
|
|
|
34
35
|
void loadProgress(int percent);
|
|
35
36
|
void canGoBackChanged(bool);
|
|
36
37
|
void canGoForwardChanged(bool);
|
|
38
|
+
|
|
37
39
|
|
|
38
40
|
|
|
39
41
|
void downloadStarted(const QString& suggestedFilename, const QString& destinationPath);
|
|
@@ -92,6 +92,10 @@ static NSString* FIT_T(NSString* key) {
|
|
|
92
92
|
@"menu.openImage": @"Open image",
|
|
93
93
|
@"menu.copyImageURL": @"Copy image URL",
|
|
94
94
|
@"menu.downloadImage":@"Download image…",
|
|
95
|
+
@"error.title": @"Can’t load this page",
|
|
96
|
+
@"error.reason": @"The site may not exist or be temporarily unreachable.",
|
|
97
|
+
@"error.retry": @"Retry",
|
|
98
|
+
@"error.close": @"Close",
|
|
95
99
|
};
|
|
96
100
|
it = @{
|
|
97
101
|
@"menu.openLink": @"Apri link",
|
|
@@ -99,6 +103,10 @@ static NSString* FIT_T(NSString* key) {
|
|
|
99
103
|
@"menu.openImage": @"Apri immagine",
|
|
100
104
|
@"menu.copyImageURL": @"Copia URL immagine",
|
|
101
105
|
@"menu.downloadImage":@"Scarica immagine…",
|
|
106
|
+
@"error.title": @"Impossibile caricare la pagina",
|
|
107
|
+
@"error.reason": @"Il sito potrebbe essere inesistente o momentaneamente non raggiungibile.",
|
|
108
|
+
@"error.retry": @"Riprova",
|
|
109
|
+
@"error.close": @"Chiudi",
|
|
102
110
|
};
|
|
103
111
|
});
|
|
104
112
|
NSString *lang = FIT_CurrentLang();
|
|
@@ -343,7 +351,7 @@ createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration
|
|
|
343
351
|
// salva coppia padre/figlio per il “ritorno” post-download
|
|
344
352
|
self.pendingPopupParentURL = parent;
|
|
345
353
|
self.pendingPopupChildURL = child;
|
|
346
|
-
|
|
354
|
+
|
|
347
355
|
if (child) {
|
|
348
356
|
[webView loadRequest:navigationAction.request]; // apri nella stessa webview
|
|
349
357
|
}
|
|
@@ -353,6 +361,26 @@ createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration
|
|
|
353
361
|
}
|
|
354
362
|
|
|
355
363
|
|
|
364
|
+
- (void)webView:(WKWebView *)webView
|
|
365
|
+
didFailProvisionalNavigation:(WKNavigation *)navigation
|
|
366
|
+
withError:(NSError *)error
|
|
367
|
+
{
|
|
368
|
+
if (!self.owner) return;
|
|
369
|
+
emit self.owner->loadFinished(false);
|
|
370
|
+
emit self.owner->loadProgress(0);
|
|
371
|
+
emit self.owner->canGoBackChanged(webView.canGoBack);
|
|
372
|
+
emit self.owner->canGoForwardChanged(webView.canGoForward);
|
|
373
|
+
|
|
374
|
+
QUrl qurl = webView.URL
|
|
375
|
+
? QUrl::fromEncoded(QByteArray(webView.URL.absoluteString.UTF8String))
|
|
376
|
+
: QUrl();
|
|
377
|
+
self.owner->renderErrorPage(qurl,
|
|
378
|
+
QString::fromUtf8(error.localizedDescription.UTF8String),
|
|
379
|
+
/*httpStatus*/ 0);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
|
|
356
384
|
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
|
|
357
385
|
if (!self.owner) return;
|
|
358
386
|
if (webView.URL)
|
|
@@ -395,6 +423,13 @@ createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration
|
|
|
395
423
|
emit self.owner->loadProgress(0);
|
|
396
424
|
emit self.owner->canGoBackChanged(webView.canGoBack);
|
|
397
425
|
emit self.owner->canGoForwardChanged(webView.canGoForward);
|
|
426
|
+
// Mostra pagina d'errore interna
|
|
427
|
+
QUrl qurl = webView.URL
|
|
428
|
+
? QUrl::fromEncoded(QByteArray(webView.URL.absoluteString.UTF8String))
|
|
429
|
+
: QUrl();
|
|
430
|
+
self.owner->renderErrorPage(qurl,
|
|
431
|
+
QString::fromUtf8(error.localizedDescription.UTF8String),
|
|
432
|
+
/*httpStatus*/ 0);
|
|
398
433
|
}
|
|
399
434
|
|
|
400
435
|
#pragma mark - Decide download vs render
|
|
@@ -413,6 +448,15 @@ decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
|
|
|
413
448
|
if (cd && [[cd lowercaseString] containsString:@"attachment"]) {
|
|
414
449
|
isAttachment = YES;
|
|
415
450
|
}
|
|
451
|
+
// 🔎 Se è main frame e status HTTP >= 400, mostra pagina d'errore custom
|
|
452
|
+
if (navigationResponse.isForMainFrame && http.statusCode >= 400 && self.owner) {
|
|
453
|
+
QUrl qurl = QUrl::fromEncoded(QByteArray(url.absoluteString.UTF8String));
|
|
454
|
+
self.owner->renderErrorPage(qurl,
|
|
455
|
+
QStringLiteral(""), // reason generica localizzata dal template
|
|
456
|
+
(int)http.statusCode);
|
|
457
|
+
decisionHandler(WKNavigationResponsePolicyCancel);
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
416
460
|
}
|
|
417
461
|
|
|
418
462
|
if (isAttachment) {
|
|
@@ -874,4 +918,87 @@ void WKWebViewWidget::setDownloadDirectory(const QString& dirPath) {
|
|
|
874
918
|
if (p.isEmpty()) return;
|
|
875
919
|
QDir().mkpath(p);
|
|
876
920
|
d->downloadDir = p;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
void WKWebViewWidget::renderErrorPage(const QUrl& url,
|
|
924
|
+
const QString& reason,
|
|
925
|
+
int httpStatus)
|
|
926
|
+
{
|
|
927
|
+
if (!(d && d->wk)) return;
|
|
928
|
+
|
|
929
|
+
// Template HTML minimale, con testo bilingue (IT/EN tramite FIT_T).
|
|
930
|
+
// Segnaposti: {url}, {reason}, {status}, {title}, {retry}, {close}
|
|
931
|
+
QString html = QString::fromUtf8(
|
|
932
|
+
R"FWB(<!doctype html><html lang="it"><meta charset="utf-8">
|
|
933
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
934
|
+
<title>{title}</title>
|
|
935
|
+
<style>
|
|
936
|
+
:root { color-scheme: light dark; }
|
|
937
|
+
html,body{height:100%}
|
|
938
|
+
body{
|
|
939
|
+
font-family:system-ui,-apple-system,Segoe UI,Roboto,Arial;
|
|
940
|
+
margin:0;background:#fff;color:#000
|
|
941
|
+
}
|
|
942
|
+
@media (prefers-color-scheme: dark){
|
|
943
|
+
body{background:#000;color:#fff}
|
|
944
|
+
}
|
|
945
|
+
.card{
|
|
946
|
+
max-width:720px;margin:8vh auto;padding:28px;border-radius:16px;
|
|
947
|
+
background:#fff;color:#000;box-shadow:0 6px 24px rgba(0,0,0,.18)
|
|
948
|
+
}
|
|
949
|
+
@media (prefers-color-scheme: dark){
|
|
950
|
+
.card{background:#111;color:#eee;box-shadow:0 6px 24px rgba(255,255,255,.05)}
|
|
951
|
+
}
|
|
952
|
+
h1{font-size:22px;margin:0 0 6px}
|
|
953
|
+
p{line-height:1.5}
|
|
954
|
+
code{
|
|
955
|
+
background:#eee;color:#000;padding:2px 6px;border-radius:6px
|
|
956
|
+
}
|
|
957
|
+
@media (prefers-color-scheme: dark){
|
|
958
|
+
code{background:#222;color:#fff}
|
|
959
|
+
}
|
|
960
|
+
.actions{margin-top:18px;display:flex;gap:10px;flex-wrap:wrap}
|
|
961
|
+
button,a{
|
|
962
|
+
padding:10px 14px;border-radius:10px;border:1px solid currentColor;
|
|
963
|
+
cursor:pointer;text-decoration:none;background:transparent;color:inherit
|
|
964
|
+
}
|
|
965
|
+
button.primary{
|
|
966
|
+
background:#000;color:#fff;border-color:#000
|
|
967
|
+
}
|
|
968
|
+
@media (prefers-color-scheme: dark){
|
|
969
|
+
button.primary{background:#fff;color:#000;border-color:#fff}
|
|
970
|
+
}
|
|
971
|
+
small{opacity:.7}
|
|
972
|
+
</style>
|
|
973
|
+
<div class="card">
|
|
974
|
+
<h1>{title}</h1>
|
|
975
|
+
<p>URL: <code>{url}</code></p>
|
|
976
|
+
<p>{reason} <small>{status}</small></p>
|
|
977
|
+
<div class="actions">
|
|
978
|
+
<button class="primary" onclick="location.reload()">{retry}</button>
|
|
979
|
+
<a class="ghost" href="about:blank">{close}</a>
|
|
980
|
+
</div>
|
|
981
|
+
</div>)FWB"
|
|
982
|
+
);
|
|
983
|
+
|
|
984
|
+
|
|
985
|
+
|
|
986
|
+
// Localizza con FIT_T
|
|
987
|
+
QString title = QString::fromUtf8([FIT_T(@"error.title") UTF8String]);
|
|
988
|
+
QString reasonText = reason.isEmpty()
|
|
989
|
+
? QString::fromUtf8([FIT_T(@"error.reason") UTF8String])
|
|
990
|
+
: reason;
|
|
991
|
+
QString retry = QString::fromUtf8([FIT_T(@"error.retry") UTF8String]);
|
|
992
|
+
QString close = QString::fromUtf8([FIT_T(@"error.close") UTF8String]);
|
|
993
|
+
|
|
994
|
+
html.replace("{title}", title);
|
|
995
|
+
html.replace("{url}", url.toString());
|
|
996
|
+
html.replace("{reason}", reasonText);
|
|
997
|
+
html.replace("{status}", httpStatus > 0 ? QString("HTTP %1").arg(httpStatus) : QString());
|
|
998
|
+
html.replace("{retry}", retry);
|
|
999
|
+
html.replace("{close}", close);
|
|
1000
|
+
|
|
1001
|
+
// Carica l'HTML direttamente nella webview
|
|
1002
|
+
[d->wk loadHTMLString:[NSString stringWithUTF8String:html.toUtf8().constData()]
|
|
1003
|
+
baseURL:[NSURL URLWithString:@"about:blank"]];
|
|
877
1004
|
}
|
{fit_webview_bridge-0.2.3a2 → fit_webview_bridge-0.2.4a1}/.github/workflows/wheels-macos.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fit_webview_bridge-0.2.3a2 → fit_webview_bridge-0.2.4a1}/bindings/pyside6/macos/CMakeLists.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|