Introduce lib/utils/log.dart (logError / logWarning over dart:developer) and route all 53 previously-bare `catch (_)` blocks through it. Behaviour is unchanged: every fallback still fails soft (a broken sidecar, unreadable file or unsupported platform must never crash a presentation) but the cause is now observable. logError is used for unexpected parse/IO failures, logWarning for expected best-effort fallbacks; no deck or file contents are ever logged. Note: file_service, markdown_service, marp_html_service, fullscreen_presenter, image_carousel_picker and url_launcher_util also carried pre-existing local changes, bundled here. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
29 lines
1.1 KiB
Dart
29 lines
1.1 KiB
Dart
import 'package:url_launcher/url_launcher.dart';
|
|
import 'log.dart';
|
|
|
|
/// Schemes a deck link may open. Anything else (file:, javascript:, custom app
|
|
/// schemes, …) is refused so a deck can't hand the OS a dangerous or
|
|
/// unexpected URI.
|
|
const _allowedUrlSchemes = {'https', 'http', 'mailto'};
|
|
|
|
/// Open een link uit slide-tekst in de externe browser. Kale domeinen
|
|
/// (zonder schema) krijgen automatisch `https://`. Faalt stil bij ongeldige,
|
|
/// niet-openbare of niet-toegestane URLs.
|
|
Future<void> openExternalUrl(String url) async {
|
|
var u = url.trim();
|
|
if (u.isEmpty) return;
|
|
if (!u.contains('://') && !u.startsWith('mailto:')) {
|
|
u = u.contains('@') ? 'mailto:$u' : 'https://$u';
|
|
}
|
|
final uri = Uri.tryParse(u);
|
|
if (uri == null) return;
|
|
if (!_allowedUrlSchemes.contains(uri.scheme.toLowerCase())) return;
|
|
try {
|
|
if (await canLaunchUrl(uri)) {
|
|
await launchUrl(uri, mode: LaunchMode.externalApplication);
|
|
}
|
|
} catch (e) {
|
|
logWarning('openExternalUrl: launching external URL failed', e);
|
|
// Nooit de presentatie laten crashen op een kapotte link.
|
|
}
|
|
}
|