Skip to content

Commit

Permalink
feat: preview pdf on web client
Browse files Browse the repository at this point in the history
  • Loading branch information
Julian KOUNE committed Oct 5, 2023
1 parent a18dcf2 commit 4ebc7d2
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 28 deletions.
5 changes: 4 additions & 1 deletion assets/l10n/intl_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -2754,5 +2754,8 @@
"workIdentitiesInfo": "WORK IDENTITIES INFO",
"editWorkIdentitiesDescriptions": "Edit your work identity settings such as Matrix ID, email or company name.",
"copiedMatrixIdToClipboard": "Copied Matrix ID to clipboard.",
"changeProfilePhoto": "Change profile photo"
"changeProfilePhoto": "Change profile photo",
"roomCreationFailed": "Room creation failed",
"errorGettingPdf": "Error getting PDF",
"errorPreviewingFile": "Error previewing file"
}
48 changes: 36 additions & 12 deletions lib/domain/model/extensions/mime_type_extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,26 @@ extension MediaTypeExtension on Event {
'AttachmentExtension::getIcon(): mediaType: $mimeType || fileType: $fileType',
);
if (mimeType?.isEmpty == true || fileType == null) {
return ImagePaths.icFileUnKnow;
return ImagePaths.icFileUnknown;
}
if (isDocFile()) {
return ImagePaths.icFileDocx;
} else if (isExcelFile()) {
return ImagePaths.icFileXlsx;
} else if (isPowerPointFile()) {
return ImagePaths.icFilePptx;
} else if (isPdfFile()) {
return ImagePaths.icFilePdf;
} else if (isZipFile()) {
return ImagePaths.icFileZip;

switch (getPreviewIconFileType()) {
case SupportedIconFileTypesEnum.image:
return ImagePaths.icFileUnknown;
case SupportedIconFileTypesEnum.doc:
return ImagePaths.icFileDocx;
case SupportedIconFileTypesEnum.excel:
return ImagePaths.icFileXlsx;
case SupportedIconFileTypesEnum.powerPoint:
return ImagePaths.icFilePptx;
case SupportedIconFileTypesEnum.pdf:
return ImagePaths.icFilePdf;
case SupportedIconFileTypesEnum.zip:
return ImagePaths.icFileZip;
case SupportedIconFileTypesEnum.unknown:
default:
return ImagePaths.icFileUnknown;
}
return ImagePaths.icFileUnKnow;
}

String getFileType(BuildContext context) {
Expand All @@ -70,4 +76,22 @@ extension MediaTypeExtension on Event {
return L10n.of(context)!.file.toUpperCase();
}
}

SupportedIconFileTypesEnum getPreviewIconFileType() {
if (isImageFile()) {
return SupportedIconFileTypesEnum.image;
} else if (isDocFile()) {
return SupportedIconFileTypesEnum.doc;
} else if (isExcelFile()) {
return SupportedIconFileTypesEnum.excel;
} else if (isPowerPointFile()) {
return SupportedIconFileTypesEnum.powerPoint;
} else if (isPdfFile()) {
return SupportedIconFileTypesEnum.pdf;
} else if (isZipFile()) {
return SupportedIconFileTypesEnum.zip;
} else {
return SupportedIconFileTypesEnum.unknown;
}
}
}
10 changes: 10 additions & 0 deletions lib/domain/model/preview_file/supported_preview_file_types.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
enum SupportedIconFileTypesEnum {
image,
doc,
excel,
powerPoint,
pdf,
zip,
unknown,
}

class SupportedPreviewFileTypes {
static const imageMimeTypes = [
'image/bmp',
Expand Down
52 changes: 46 additions & 6 deletions lib/pages/chat/chat.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'package:fluffychat/domain/app_state/preview_file/download_file_for_previ
import 'package:fluffychat/domain/app_state/preview_file/download_file_for_preview_loading.dart';
import 'package:fluffychat/domain/app_state/preview_file/download_file_for_preview_success.dart';
import 'package:fluffychat/domain/model/download_file/download_file_for_preview_response.dart';
import 'package:fluffychat/domain/model/extensions/mime_type_extension.dart';
import 'package:fluffychat/domain/model/preview_file/document_uti.dart';
import 'package:fluffychat/domain/model/preview_file/supported_preview_file_types.dart';
import 'package:fluffychat/domain/usecase/download_file_for_preview_interactor.dart';
Expand Down Expand Up @@ -62,6 +63,7 @@ import 'package:record/record.dart';
import 'package:scroll_to_index/scroll_to_index.dart';
import 'package:share_plus/share_plus.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:universal_html/html.dart' as html;

import '../../utils/account_bundles.dart';
import '../../utils/localized_exception_extension.dart';
Expand Down Expand Up @@ -511,7 +513,19 @@ class ChatController extends State<Chat>
});
}

void onFileTapped(Event event) async {
void onFileTapped(Event event) {
if (PlatformInfos.isWeb) {
onFileTappedWeb(event);
} else {
onFileTappedMobile(event);
}
}

void onFileTappedWeb(Event event) {
return _handlePreviewWeb(event: event);
}

void onFileTappedMobile(Event event) async {
final permissionHandler = PermissionHandlerService();
final storagePermissionStatus =
await permissionHandler.storagePermissionStatus;
Expand All @@ -531,11 +545,11 @@ class ChatController extends State<Chat>
);
if (await permissionHandler.storagePermissionStatus ==
PermissionStatus.granted) {
_handleDownloadFileForPreview(event: event);
_handleDownloadFileForPreviewMobile(event: event);
}
break;
case PermissionStatus.granted:
_handleDownloadFileForPreview(event: event);
_handleDownloadFileForPreviewMobile(event: event);
break;
case PermissionStatus.permanentlyDenied:
showDialog(
Expand All @@ -560,7 +574,20 @@ class ChatController extends State<Chat>
}
}

void _handleDownloadFileForPreview({required Event event}) async {
void _handlePreviewWeb({required Event event}) async {
if (!event.hasAttachment) {
Fluttertoast.showToast(msg: L10n.of(context)!.errorPreviewingFile);
return;
}

if (event.isPdfFile()) {
return previewPdfWeb(context, event);
}

downloadFileAction(context, event);
}

void _handleDownloadFileForPreviewMobile({required Event event}) async {
final downloadFileForPreviewInteractor =
getIt.get<DownloadFileForPreviewInteractor>();
final tempDirPath = (await getTemporaryDirectory()).path;
Expand Down Expand Up @@ -1469,8 +1496,21 @@ class ChatController extends State<Chat>
}
}

void downloadFileAction(BuildContext context, Event event) =>
event.saveFile(context);
Future<String?> downloadFileAction(BuildContext context, Event event) async =>
await event.saveFile(context);

void previewPdfWeb(BuildContext context, Event event) async {
final pdf = await event.getFile(context);
if (pdf.result == null || event.sizeString != pdf.result?.sizeString) {
Fluttertoast.showToast(msg: L10n.of(context)!.errorGettingPdf);
return;
}

final blob = html.Blob([pdf.result!.bytes], 'application/pdf');
final url = html.Url.createObjectUrlFromBlob(blob);
html.window.open(url, "_blank");
html.Url.revokeObjectUrl(url);
}

void handleContextMenuAction(
BuildContext context,
Expand Down
3 changes: 2 additions & 1 deletion lib/pages/chat_draft/draft_chat.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import 'package:linagora_design_flutter/images_picker/images_picker.dart'
hide ImagePicker;
import 'package:matrix/matrix.dart';
import 'package:scroll_to_index/scroll_to_index.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';

typedef OnRoomCreatedSuccess = FutureOr<void> Function(Room room)?;
typedef OnRoomCreatedFailed = FutureOr<void> Function()?;
Expand Down Expand Up @@ -238,7 +239,7 @@ class DraftChatController extends State<DraftChat>
void onInputBarSubmitted(_) {
sendText(
onCreateRoomFailed: () {
Fluttertoast.showToast(msg: 'Create room failed');
Fluttertoast.showToast(msg: L10n.of(context)!.roomCreationFailed);
FocusScope.of(context).requestFocus(inputFocus);
},
);
Expand Down
2 changes: 1 addition & 1 deletion lib/resource/image_paths.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class ImagePaths {
static String get icFilePdf => _getImagePath('ic_file_pdf.svg');
static String get icFilePptx => _getImagePath('ic_file_ppt.svg');
static String get icFileFolder => _getImagePath('ic_file_folder.svg');
static String get icFileUnKnow => _getImagePath('ic_file_unknow.svg');
static String get icFileUnknown => _getImagePath('ic_file_unknow.svg');
static String get icTwakeImageLogoDark =>
_getImagePath('ic_twake_image_logo_dark.svg');
static String get icApplicationGrid =>
Expand Down
4 changes: 2 additions & 2 deletions lib/utils/matrix_sdk_extensions/event_extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ extension LocalizedBody on Event {
future: downloadAndDecryptAttachment,
);

void saveFile(BuildContext context) async {
Future<String?> saveFile(BuildContext context) async {
final matrixFile = await getFile(context);

matrixFile.result?.downloadFile(context);
return await matrixFile.result?.downloadFile(context);
}

String get filename {
Expand Down
18 changes: 13 additions & 5 deletions lib/utils/matrix_sdk_extensions/matrix_file_extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,18 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:file_saver/file_saver.dart';

extension MatrixFileExtension on MatrixFile {
void downloadFile(BuildContext context) async {
Future<String?> downloadFile(BuildContext context) async {
if (PlatformInfos.isWeb) {
return downloadFileInWeb(context);
return await downloadFileInWeb(context);
}

if (PlatformInfos.isMobile) {
return downloadImageInMobile(context);
return await downloadImageInMobile(context);
}

throw UnsupportedError(
'Download feature is not supported on this platform',
);
}

void share(BuildContext context) async {
Expand All @@ -40,7 +44,7 @@ extension MatrixFileExtension on MatrixFile {
return;
}

void downloadFileInWeb(BuildContext context) async {
Future<String> downloadFileInWeb(BuildContext context) async {
Logs().d("MatrixFileExtension()::downloadFileInWeb()::download on Web");

final directory = await FileSaver.instance.saveFile(
Expand All @@ -53,9 +57,11 @@ extension MatrixFileExtension on MatrixFile {
Fluttertoast.showToast(
msg: L10n.of(context)!.downloadFileInWeb(directory),
);

return '$directory/$name';
}

void downloadImageInMobile(BuildContext context) async {
Future<String> downloadImageInMobile(BuildContext context) async {
Logs().d(
"MatrixFileExtension()::downloadImageInMobile()::download on Mobile",
);
Expand All @@ -70,6 +76,8 @@ extension MatrixFileExtension on MatrixFile {
? L10n.of(context)!.downloadImageSuccess
: L10n.of(context)!.downloadImageError,
);

return result?['filePath'] ?? '';
}

FileType get filePickerFileType {
Expand Down

0 comments on commit 4ebc7d2

Please sign in to comment.