added a swipeable media gallery for chat and folder images and videos with server previews, on-demand originals and zoom, and marked document previews in chat so they no longer pass for photos

This commit is contained in:
MineTec committed 2026-10-28 22:15:57 +01:00
1 parent 952f916231
commit aa176c90e3
22 files changed
+1658 -103

No files matched your search

+3 -49
View File
@@ -3,14 +3,12 @@ import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:open_filex/open_filex.dart';
import 'package:photo_view/photo_view.dart';
import 'package:share_plus/share_plus.dart';
import '../routing/app_routes.dart';
import '../share_intent/remote_file_ref.dart';
@@ -18,16 +16,15 @@ import '../state/app/modules/settings/bloc/settings_cubit.dart';
import '../utils/downloads/download_manager.dart';
import '../utils/screen_bound_image.dart';
import 'app_progress_indicator.dart';
import 'async_action_button.dart';
import 'centered_leading.dart';
import 'downloads/stale_download_guard.dart';
import 'file_viewer/code_line.dart';
import 'file_viewer/deferred_pdf_viewer.dart';
import 'file_viewer/file_kind.dart';
import 'file_viewer/local_file_actions.dart';
import 'file_viewer/media_player.dart';
import 'file_viewer/unknown_preview_block.dart';
import 'info_dialog.dart';
import 'share_position_origin.dart';
class FileViewer extends StatefulWidget {
final String path;
@@ -137,54 +134,11 @@ class _FileViewerState extends State<FileViewer> {
break;
case FileViewingActions.share:
if (!_ensureLocalFile()) return;
unawaited(
runWithErrorDialog(
context,
() => SharePlus.instance.share(
ShareParams(
files: [XFile(widget.path)],
sharePositionOrigin: SharePositionOrigin.get(context),
),
),
),
);
unawaited(shareLocalFile(context, widget.path));
break;
case FileViewingActions.save:
if (!_ensureLocalFile()) return;
try {
final source = File(widget.path);
final size = await source.length();
// file_picker has no path/stream save API, so the whole file
// gets loaded into RAM. Cap big media; user falls back to share.
const maxBytes = 200 * 1024 * 1024;
if (size > maxBytes) {
if (!mounted) return;
InfoDialog.show(
context,
'Diese Datei ist zu groß (${(size / (1024 * 1024)).toStringAsFixed(0)} MB), '
'um direkt gespeichert zu werden. Nutze stattdessen die Teilen-Funktion.',
title: 'Speichern nicht möglich',
);
return;
}
final bytes = await source.readAsBytes();
final saved = await FilePicker.saveFile(
fileName: _fileName,
bytes: bytes,
);
if (!mounted) return;
if (saved != null) {
InfoDialog.show(context, 'Datei gespeichert.');
}
} on Object catch (e) {
if (!mounted) return;
InfoDialog.show(
context,
'Speichern fehlgeschlagen: $e',
copyable: true,
title: 'Fehler',
);
}
await saveLocalFile(context, widget.path);
break;
}
}