diff --git a/b0esche_cloud/lib/pages/public_file_viewer.dart b/b0esche_cloud/lib/pages/public_file_viewer.dart index 8726556..8c6051c 100644 --- a/b0esche_cloud/lib/pages/public_file_viewer.dart +++ b/b0esche_cloud/lib/pages/public_file_viewer.dart @@ -1,3 +1,4 @@ +import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:web/web.dart' as web; @@ -23,6 +24,7 @@ class _PublicFileViewerState extends State { String? _error; Map? _fileData; VideoPlayerController? _videoController; + List? _pdfBytes; @override void initState() { @@ -46,6 +48,11 @@ class _PublicFileViewerState extends State { _isLoading = false; }); + // Load PDF bytes if it's a PDF file + if (_isPdfFile()) { + await _loadPdfBytes(); + } + // Initialize video controller if it's a video file if (_isVideoFile()) { _initializeVideoPlayer(); @@ -58,6 +65,28 @@ class _PublicFileViewerState extends State { } } + Future _loadPdfBytes() async { + if (_fileData?['viewUrl'] != null) { + try { + final apiClient = getIt(); + // Extract the path from viewUrl and call it directly + final viewUrl = _fileData!['viewUrl'] as String; + final uri = Uri.parse(viewUrl); + final path = uri.path + (uri.query.isNotEmpty ? '?${uri.query}' : ''); + + final bytes = await apiClient.getBytes(path); + setState(() { + _pdfBytes = bytes; + }); + } catch (e) { + // If loading fails, we'll show an error or fallback + setState(() { + _error = 'Failed to load PDF content.'; + }); + } + } + } + Future _initializeVideoPlayer() async { final url = _fileData?['viewUrl'] ?? _fileData?['downloadUrl']; if (url != null) { @@ -115,15 +144,35 @@ class _PublicFileViewerState extends State { if (viewUrl == null) return const SizedBox(); if (_isPdfFile()) { - return Expanded( - child: SfPdfViewer.network( - viewUrl, - canShowScrollHead: false, - canShowScrollStatus: false, - enableDoubleTapZooming: true, - enableTextSelection: false, - ), - ); + if (_pdfBytes != null) { + return Expanded( + child: SfPdfViewer.memory( + Uint8List.fromList(_pdfBytes!), + canShowScrollHead: false, + canShowScrollStatus: false, + enableDoubleTapZooming: true, + enableTextSelection: false, + ), + ); + } else if (_error != null) { + return Expanded( + child: Center( + child: Text( + _error!, + style: TextStyle(color: AppTheme.primaryText), + textAlign: TextAlign.center, + ), + ), + ); + } else { + return const Expanded( + child: Center( + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(AppTheme.accentColor), + ), + ), + ); + } } else if (_isVideoFile() && _videoController != null) { return Expanded( child: AspectRatio( diff --git a/b0esche_cloud/lib/services/api_client.dart b/b0esche_cloud/lib/services/api_client.dart index 6fcacae..9635df2 100644 --- a/b0esche_cloud/lib/services/api_client.dart +++ b/b0esche_cloud/lib/services/api_client.dart @@ -97,6 +97,18 @@ class ApiClient { } } + Future> getBytes(String path) async { + try { + final response = await _dio.get( + path, + options: Options(responseType: ResponseType.bytes), + ); + return response.data; + } on DioException catch (e) { + throw _handleError(e); + } + } + Future> postRaw(String path, {dynamic data}) async { try { final response = await _dio.post(path, data: data);