Skip to content

Commit

Permalink
Merge pull request #1444 from ardriveapp/PE-4709
Browse files Browse the repository at this point in the history
PE-4709: Image preview on Shared File Page
  • Loading branch information
matibat authored Nov 2, 2023
2 parents 748697e + 077341f commit 0676af2
Show file tree
Hide file tree
Showing 3 changed files with 231 additions and 12 deletions.
33 changes: 28 additions & 5 deletions lib/blocs/fs_entry_preview/fs_entry_preview_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import 'package:ardrive/models/models.dart';
import 'package:ardrive/pages/pages.dart';
import 'package:ardrive/services/services.dart';
import 'package:ardrive/utils/constants.dart';
import 'package:ardrive/utils/mime_lookup.dart';
import 'package:ardrive_http/ardrive_http.dart';
import 'package:ardrive_io/ardrive_io.dart';
import 'package:ardrive_utils/ardrive_utils.dart';
import 'package:cryptography/cryptography.dart';
import 'package:drift/drift.dart';
Expand Down Expand Up @@ -79,7 +79,12 @@ class FsEntryPreviewCubit extends Cubit<FsEntryPreviewState> {
final data = await _getPreviewData(file, previewUrl);

if (data != null) {
emit(FsEntryPreviewImage(imageBytes: data, previewUrl: previewUrl));
emit(FsEntryPreviewImage(
imageBytes: data,
previewUrl: previewUrl,
filename: file.name,
contentType: file.contentType,
));
} else {
emit(FsEntryPreviewUnavailable());
}
Expand Down Expand Up @@ -280,7 +285,13 @@ class FsEntryPreviewCubit extends Cubit<FsEntryPreviewState> {
switch (drive.privacy) {
case DrivePrivacyTag.public:
emit(
FsEntryPreviewImage(imageBytes: dataBytes, previewUrl: dataUrl),
FsEntryPreviewImage(
imageBytes: dataBytes,
previewUrl: dataUrl,
filename: file.name,
contentType: file.dataContentType ??
lookupMimeTypeWithDefaultType(file.name),
),
);
break;
case DrivePrivacyTag.private:
Expand All @@ -291,7 +302,13 @@ class FsEntryPreviewCubit extends Cubit<FsEntryPreviewState> {

if (isPinFile) {
emit(
FsEntryPreviewImage(imageBytes: dataBytes, previewUrl: dataUrl),
FsEntryPreviewImage(
imageBytes: dataBytes,
previewUrl: dataUrl,
filename: file.name,
contentType: file.dataContentType ??
lookupMimeTypeWithDefaultType(file.name),
),
);
break;
}
Expand All @@ -316,7 +333,13 @@ class FsEntryPreviewCubit extends Cubit<FsEntryPreviewState> {
fileKey,
);
emit(
FsEntryPreviewImage(imageBytes: decodedBytes, previewUrl: dataUrl),
FsEntryPreviewImage(
imageBytes: decodedBytes,
previewUrl: dataUrl,
filename: file.name,
contentType: file.dataContentType ??
lookupMimeTypeWithDefaultType(file.name),
),
);
break;

Expand Down
4 changes: 4 additions & 0 deletions lib/blocs/fs_entry_preview/fs_entry_preview_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@ class FsEntryPreviewLoading extends FsEntryPreviewSuccess {

class FsEntryPreviewImage extends FsEntryPreviewSuccess {
final Uint8List imageBytes;
final String filename;
final String contentType;

const FsEntryPreviewImage({
required this.imageBytes,
required this.filename,
required this.contentType,
required String previewUrl,
}) : super(previewUrl: previewUrl);

Expand Down
206 changes: 199 additions & 7 deletions lib/pages/drive_detail/components/fs_entry_preview_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,12 @@ class _FsEntryPreviewWidgetState extends State<FsEntryPreviewWidget> {
);

case FsEntryPreviewImage:
return ArDriveImage(
fit: BoxFit.contain,
height: double.maxFinite,
width: double.maxFinite,
image: MemoryImage(
(widget.state as FsEntryPreviewImage).imageBytes,
),
return ImagePreviewWidget(
filename: (widget.state as FsEntryPreviewImage).filename,
contentType: (widget.state as FsEntryPreviewImage).contentType,
imageBytes: (widget.state as FsEntryPreviewImage).imageBytes,
isSharePage: widget.isSharePage,
isFullScreen: false,
);

case FsEntryPreviewAudio:
Expand Down Expand Up @@ -1033,6 +1032,199 @@ class _FullScreenVideoPlayerWidgetState
}
}

class ImagePreviewFullScreenWidget extends StatefulWidget {
final Uint8List imageBytes;
final String filename;
final String contentType;

const ImagePreviewFullScreenWidget({
super.key,
required this.filename,
required this.contentType,
required this.imageBytes,
});

@override
State<StatefulWidget> createState() {
return _ImagePreviewFullScreenWidgetState();
}
}

class _ImagePreviewFullScreenWidgetState
extends State<ImagePreviewFullScreenWidget> {
bool fullScreenMode = false;

@override
void initState() {
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
DeviceOrientation.landscapeLeft,
]);

super.initState();
}

@override
void dispose() {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);

super.dispose();
}

@override
Widget build(BuildContext context) {
return Scaffold(
body: ImagePreviewWidget(
filename: widget.filename,
contentType: widget.contentType,
imageBytes: widget.imageBytes,
isFullScreen: true,
),
);
}
}

class ImagePreviewWidget extends StatefulWidget {
final Uint8List imageBytes;
final String filename;
final String contentType;
final bool isSharePage;
final bool isFullScreen;

const ImagePreviewWidget({
super.key,
required this.filename,
required this.contentType,
required this.imageBytes,
this.isSharePage = false,
this.isFullScreen = false,
});

@override
State<StatefulWidget> createState() {
return _ImagePreviewWidgetState();
}
}

class _ImagePreviewWidgetState extends State<ImagePreviewWidget> {
@override
Widget build(BuildContext context) {
if (!widget.isSharePage && !widget.isFullScreen) {
return _buildImage();
} else {
final theme = ArDriveTheme.of(context);

return Column(
children: [
Flexible(child: _buildImage()),
Container(
color: theme.themeData.colors.themeBgCanvas,
child: _buildActionBar(),
),
],
);
}
}

Widget _buildImage() {
return ArDriveImage(
fit: BoxFit.contain,
height: double.maxFinite,
width: double.maxFinite,
image: MemoryImage(
widget.imageBytes,
),
);
}

Widget _buildActionBar() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
height: 96,
child: Padding(
padding: const EdgeInsets.only(
left: 24,
top: 24,
bottom: 24,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
_getFileNameWithNoExtension(),
style: ArDriveTypography.body.smallBold700(
color: ArDriveTheme.of(context)
.themeData
.colors
.themeFgDefault,
),
),
Text(
_getFileExtension(),
style: ArDriveTypography.body.smallRegular(
color: ArDriveTheme.of(context)
.themeData
.colors
.themeFgDisabled,
),
),
],
),
),
),
Padding(
padding: const EdgeInsets.only(
right: 24,
top: 24,
bottom: 24,
),
child: IconButton(
onPressed: goFullScreen,
icon: widget.isFullScreen
? const Icon(Icons.fullscreen_exit_outlined)
: const Icon(Icons.fullscreen_outlined, size: 24),
),
),
],
);
}

String _getFileNameWithNoExtension() {
return widget.filename.substring(0, widget.filename.lastIndexOf('.'));
}

String _getFileExtension() {
return widget.contentType
.substring(
widget.contentType.lastIndexOf('/') + 1,
)
.toUpperCase();
}

void goFullScreen() {
if (widget.isFullScreen) {
Navigator.of(context).pop();
} else {
Navigator.of(context).push(
PageRouteBuilder(
transitionDuration: Duration.zero,
reverseTransitionDuration: Duration.zero,
pageBuilder: (context, _, __) => ImagePreviewFullScreenWidget(
filename: widget.filename,
contentType: widget.contentType,
imageBytes: widget.imageBytes,
),
),
);
}
}
}

class AudioPlayerWidget extends StatefulWidget {
final String audioUrl;
final String filename;
Expand Down

0 comments on commit 0676af2

Please sign in to comment.