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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: fit-webview-bridge
3
- Version: 0.2.3a2
3
+ Version: 0.2.4a1
4
4
  Summary: Qt native WebView bridge with PySide6 bindings
5
5
  Author: FIT Project
6
6
  License: LGPL-3.0-or-later
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fit-webview-bridge"
3
- version = "0.2.3a2"
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
  }