♻️ Refactored the file detail

This commit is contained in:
2025-11-15 15:04:01 +08:00
parent 4607b77355
commit 3b983a6444

View File

@@ -1,7 +1,6 @@
import 'dart:io'; import 'dart:io';
import 'dart:math' as math; import 'dart:math' as math;
import 'package:dismissible_page/dismissible_page.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:file_saver/file_saver.dart'; import 'package:file_saver/file_saver.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@@ -227,18 +226,75 @@ class FileDetailScreen extends HookConsumerWidget {
final uri = '$serverUrl/drive/files/${item.id}'; final uri = '$serverUrl/drive/files/${item.id}';
return switch (item.mimeType?.split('/').firstOrNull) { return switch (item.mimeType?.split('/').firstOrNull) {
'image' => _buildImageContent(context, ref, uri), 'image' => _ImageContent(item: item, uri: uri),
'video' => _buildVideoContent(context, ref, uri), 'video' => _VideoContent(item: item, uri: uri),
'audio' => _buildAudioContent(context, ref, uri), 'audio' => _AudioContent(item: item, uri: uri),
_ when item.mimeType == 'application/pdf' => _PdfContent(uri: uri), _ when item.mimeType == 'application/pdf' => _PdfContent(uri: uri),
_ when item.mimeType?.startsWith('text/') == true => _TextContent( _ when item.mimeType?.startsWith('text/') == true => _TextContent(
uri: uri, uri: uri,
), ),
_ => _buildGenericContent(context, ref), _ => _GenericContent(item: item),
}; };
} }
}
Widget _buildImageContent(BuildContext context, WidgetRef ref, String uri) { class _PdfContent extends HookConsumerWidget {
final String uri;
const _PdfContent({required this.uri});
@override
Widget build(BuildContext context, WidgetRef ref) {
final pdfViewer = useMemoized(() => SfPdfViewer.network(uri), [uri]);
return pdfViewer;
}
}
class _TextContent extends HookConsumerWidget {
final String uri;
const _TextContent({required this.uri});
@override
Widget build(BuildContext context, WidgetRef ref) {
final textFuture = useMemoized(
() => ref
.read(apiClientProvider)
.get(uri)
.then((response) => response.data as String),
[uri],
);
return FutureBuilder<String>(
future: textFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('Error loading text: ${snapshot.error}'));
} else if (snapshot.hasData) {
return SingleChildScrollView(
padding: EdgeInsets.all(20),
child: SelectableText(
snapshot.data!,
style: const TextStyle(fontFamily: 'monospace', fontSize: 14),
),
);
}
return const Center(child: Text('No content'));
},
);
}
}
class _ImageContent extends HookConsumerWidget {
final SnCloudFile item;
final String uri;
const _ImageContent({required this.item, required this.uri});
@override
Widget build(BuildContext context, WidgetRef ref) {
final photoViewController = useMemoized(() => PhotoViewController(), []); final photoViewController = useMemoized(() => PhotoViewController(), []);
final rotation = useState(0); final rotation = useState(0);
final showOriginal = useState(false); final showOriginal = useState(false);
@@ -247,14 +303,7 @@ class FileDetailScreen extends HookConsumerWidget {
Shadow(color: Colors.black54, blurRadius: 5.0, offset: Offset(1.0, 1.0)), Shadow(color: Colors.black54, blurRadius: 5.0, offset: Offset(1.0, 1.0)),
]; ];
return DismissiblePage( return Stack(
isFullScreen: true,
backgroundColor: Colors.transparent,
direction: DismissiblePageDismissDirection.down,
onDismissed: () {
Navigator.of(context).pop();
},
child: Stack(
children: [ children: [
Positioned.fill( Positioned.fill(
child: PhotoView( child: PhotoView(
@@ -280,11 +329,7 @@ class FileDetailScreen extends HookConsumerWidget {
child: Row( child: Row(
children: [ children: [
IconButton( IconButton(
icon: Icon( icon: Icon(Icons.remove, color: Colors.white, shadows: shadow),
Icons.remove,
color: Colors.white,
shadows: shadow,
),
onPressed: () { onPressed: () {
photoViewController.scale = photoViewController.scale =
(photoViewController.scale ?? 1) - 0.05; (photoViewController.scale ?? 1) - 0.05;
@@ -306,8 +351,7 @@ class FileDetailScreen extends HookConsumerWidget {
), ),
onPressed: () { onPressed: () {
rotation.value = (rotation.value - 1) % 4; rotation.value = (rotation.value - 1) % 4;
photoViewController.rotation = photoViewController.rotation = rotation.value * -math.pi / 2;
rotation.value * -math.pi / 2;
}, },
), ),
IconButton( IconButton(
@@ -318,8 +362,7 @@ class FileDetailScreen extends HookConsumerWidget {
), ),
onPressed: () { onPressed: () {
rotation.value = (rotation.value + 1) % 4; rotation.value = (rotation.value + 1) % 4;
photoViewController.rotation = photoViewController.rotation = rotation.value * -math.pi / 2;
rotation.value * -math.pi / 2;
}, },
), ),
const Spacer(), const Spacer(),
@@ -337,53 +380,59 @@ class FileDetailScreen extends HookConsumerWidget {
), ),
), ),
], ],
),
); );
} }
}
Widget _buildVideoContent(BuildContext context, WidgetRef ref, String uri) { class _VideoContent extends HookConsumerWidget {
final SnCloudFile item;
final String uri;
const _VideoContent({required this.item, required this.uri});
@override
Widget build(BuildContext context, WidgetRef ref) {
var ratio = var ratio =
item.fileMeta?['ratio'] is num item.fileMeta?['ratio'] is num
? item.fileMeta!['ratio'].toDouble() ? item.fileMeta!['ratio'].toDouble()
: 1.0; : 1.0;
if (ratio == 0) ratio = 1.0; if (ratio == 0) ratio = 1.0;
return DismissiblePage( return Center(
isFullScreen: true,
backgroundColor: Colors.black,
direction: DismissiblePageDismissDirection.down,
onDismissed: () {
Navigator.of(context).pop();
},
child: Center(
child: AspectRatio( child: AspectRatio(
aspectRatio: ratio, aspectRatio: ratio,
child: UniversalVideo(uri: uri, autoplay: true), child: UniversalVideo(uri: uri, autoplay: true),
), ),
),
); );
} }
}
Widget _buildAudioContent(BuildContext context, WidgetRef ref, String uri) { class _AudioContent extends HookConsumerWidget {
return DismissiblePage( final SnCloudFile item;
isFullScreen: true, final String uri;
backgroundColor: Theme.of(context).colorScheme.surface,
direction: DismissiblePageDismissDirection.down, const _AudioContent({required this.item, required this.uri});
onDismissed: () {
Navigator.of(context).pop(); @override
}, Widget build(BuildContext context, WidgetRef ref) {
child: Center( return Center(
child: ConstrainedBox( child: ConstrainedBox(
constraints: BoxConstraints( constraints: BoxConstraints(
maxWidth: math.min(360, MediaQuery.of(context).size.width * 0.8), maxWidth: math.min(360, MediaQuery.of(context).size.width * 0.8),
), ),
child: UniversalAudio(uri: uri, filename: item.name), child: UniversalAudio(uri: uri, filename: item.name),
), ),
),
); );
} }
}
Widget _buildGenericContent(BuildContext context, WidgetRef ref) { class _GenericContent extends HookConsumerWidget {
final SnCloudFile item;
const _GenericContent({required this.item});
@override
Widget build(BuildContext context, WidgetRef ref) {
Future<void> downloadFile() async { Future<void> downloadFile() async {
try { try {
showSnackBar('Downloading file...'); showSnackBar('Downloading file...');
@@ -412,14 +461,7 @@ class FileDetailScreen extends HookConsumerWidget {
} }
} }
return DismissiblePage( return Center(
isFullScreen: true,
backgroundColor: Theme.of(context).colorScheme.surface,
direction: DismissiblePageDismissDirection.down,
onDismissed: () {
Navigator.of(context).pop();
},
child: Center(
child: Container( child: Container(
margin: const EdgeInsets.all(32), margin: const EdgeInsets.all(32),
padding: const EdgeInsets.all(32), padding: const EdgeInsets.all(32),
@@ -483,56 +525,6 @@ class FileDetailScreen extends HookConsumerWidget {
], ],
), ),
), ),
),
);
}
}
class _PdfContent extends HookConsumerWidget {
final String uri;
const _PdfContent({required this.uri});
@override
Widget build(BuildContext context, WidgetRef ref) {
final pdfViewer = useMemoized(() => SfPdfViewer.network(uri), [uri]);
return pdfViewer;
}
}
class _TextContent extends HookConsumerWidget {
final String uri;
const _TextContent({required this.uri});
@override
Widget build(BuildContext context, WidgetRef ref) {
final textFuture = useMemoized(
() => ref
.read(apiClientProvider)
.get(uri)
.then((response) => response.data as String),
[uri],
);
return FutureBuilder<String>(
future: textFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('Error loading text: ${snapshot.error}'));
} else if (snapshot.hasData) {
return SingleChildScrollView(
padding: EdgeInsets.all(20),
child: SelectableText(
snapshot.data!,
style: const TextStyle(fontFamily: 'monospace', fontSize: 14),
),
);
}
return const Center(child: Text('No content'));
},
); );
} }
} }