Skip to content

Commit

Permalink
TW-1127: build UI for send file dialog and fileTile
Browse files Browse the repository at this point in the history
  • Loading branch information
sherlockvn authored and hoangdat committed Dec 26, 2023
1 parent 5e85ef5 commit 5094a01
Show file tree
Hide file tree
Showing 10 changed files with 363 additions and 119 deletions.
3 changes: 2 additions & 1 deletion assets/l10n/intl_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -2982,5 +2982,6 @@
"useYourCompanyServer": "Use your company server",
"descriptionTwakeId": "To start, please create a TwakeID \nthat will allow you to use \nchat, mail and drive",
"countFilesSendPerDialog": "The maximum files when sending is {count}.",
"sendFiles": "Send {count} files"
"sendFiles": "Send {count} files",
"failedToSendFiles": "Failed to send files"
}
13 changes: 5 additions & 8 deletions lib/pages/chat/chat.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import 'package:fluffychat/presentation/mixins/common_media_picker_mixin.dart';
import 'package:fluffychat/presentation/mixins/go_to_direct_chat_mixin.dart';
import 'package:fluffychat/presentation/mixins/media_picker_mixin.dart';
import 'package:fluffychat/presentation/mixins/send_files_mixin.dart';
import 'package:fluffychat/presentation/mixins/send_files_with_caption_web_mixin.dart';
import 'package:fluffychat/presentation/model/forward/forward_argument.dart';
import 'package:fluffychat/utils/account_bundles.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
Expand Down Expand Up @@ -83,6 +84,7 @@ class ChatController extends State<Chat>
with
CommonMediaPickerMixin,
MediaPickerMixin,
SendFilesWithCaptionWebMixin,
SendFilesMixin,
PopupContextMenuActionMixin,
PopupMenuWidgetMixin,
Expand Down Expand Up @@ -315,13 +317,7 @@ class ChatController extends State<Chat>

void handleDragDone(DropDoneDetails details) async {
final matrixFiles = await onDragDone(details);
if (room != null) {
sendImagesWithCaption(
room: room!,
context: context,
matrixFiles: matrixFiles,
);
}
sendFileOnWebAction(context, room: room, matrixFilesList: matrixFiles);
}

void _handleReceivedShareFiles() {
Expand Down Expand Up @@ -1269,7 +1265,8 @@ class ChatController extends State<Chat>
if (PlatformInfos.isMobile) {
_showMediaPicker(context);
} else {
sendFileOnWebAction(context, room: room);
final matrixFiles = await pickFilesFromSystem();
sendFileOnWebAction(context, room: room, matrixFilesList: matrixFiles);
}
}

Expand Down
85 changes: 40 additions & 45 deletions lib/pages/chat/send_file_dialog.dart
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import 'package:fluffychat/di/global/get_it_initializer.dart';
import 'package:fluffychat/domain/usecase/send_files_on_web_with_caption_interactor.dart';
import 'package:fluffychat/domain/usecase/send_media_on_web_with_caption_interactor.dart';
import 'package:fluffychat/pages/chat/input_bar/focus_suggestion_controller.dart';
import 'package:fluffychat/pages/chat/send_file_dialog_view.dart';
import 'package:fluffychat/presentation/extensions/send_file_web_extension.dart';
import 'package:fluffychat/utils/dialog/twake_dialog.dart';
import 'package:fluffychat/utils/localized_exception_extension.dart';
import 'package:fluffychat/utils/twake_snackbar.dart';
import 'package:flutter/material.dart';

import 'package:matrix/matrix.dart';

import '../../utils/resize_image.dart';

class SendFileDialog extends StatefulWidget {
final Room? room;
final List<MatrixFile> files;
Expand All @@ -27,18 +22,32 @@ class SendFileDialog extends StatefulWidget {
}

class SendFileDialogController extends State<SendFileDialog> {
bool origImage = false;

/// Images smaller than 20kb don't need compression.
static const int minSizeToCompress = 20 * 1024;

final sendMediaOnWebWithCaptionInteractor =
getIt.get<SendMediaOnWebWithCaptionInteractor>();

final sendFilesOnWebWithCaptionInteractor =
getIt.get<SendFilesOnWebWithCaptionInteractor>();

final focusSuggestionController = FocusSuggestionController();

final TextEditingController textEditingController = TextEditingController();

bool isSendMediaWithCaption = true;

List<MatrixFile> get files => widget.files;

@override
void initState() {
super.initState();
isSendMediaWithCaption = _isShowSendMediaDialog(widget.files, widget.room);
}

@override
void dispose() {
textEditingController.dispose();
super.dispose();
}

void sendMediaWithCaption() {
if (widget.room == null) {
Logs().e("sendMediaWithCaption:: room is null");
Expand All @@ -50,50 +59,36 @@ class SendFileDialogController extends State<SendFileDialog> {
media: widget.files.first,
caption: textEditingController.text,
);
Navigator.of(context).pop();
Navigator.of(context).pop(true);
}

Future<void> sendWithoutCaption() async {
for (var file in widget.files) {
// ignore: unused_local_variable
MatrixImageFile? thumbnail;
if (file is MatrixVideoFile &&
(file.bytes?.length ?? 0) > minSizeToCompress) {
await TwakeDialog.showFutureLoadingDialogFullScreen(
future: () async {
file = await file.resizeVideo();
thumbnail = await file.getVideoThumbnail();
},
);
}
if (widget.room == null) {
Logs().e("sendMediaWithCaption:: room is null");
Navigator.of(context).pop();
return;
}
widget.room!
.sendFileOnWebEvent(
file,
thumbnail: thumbnail,
)
.catchError((e) {
TwakeSnackBar.show(context, (e as Object).toLocalizedString(context));
return null;
});
void sendFilesWithCaption() {
if (widget.room == null) {
Logs().e("sendFilesWithCaption:: room is null");
Navigator.of(context).pop();
return;
}
Navigator.of(context, rootNavigator: false).pop();

return;
sendFilesOnWebWithCaptionInteractor.execute(
room: widget.room!,
files: widget.files,
caption: textEditingController.text,
);
Navigator.of(context).pop(true);
}

void send() {
if (textEditingController.text.isEmpty) {
sendWithoutCaption();
} else {
if (_isShowSendMediaDialog(widget.files, widget.room)) {
sendMediaWithCaption();
} else {
sendFilesWithCaption();
}
}

bool _isShowSendMediaDialog(List<MatrixFile> matrixFilesList, Room? room) =>
matrixFilesList.length == 1 &&
matrixFilesList.first is MatrixImageFile &&
room != null;

@override
Widget build(BuildContext context) {
return SendFileDialogView(this);
Expand Down
17 changes: 15 additions & 2 deletions lib/pages/chat/send_file_dialog_style.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
class SendFileDialogStyle {
static const dialogBorderRadius = 16.0;

static const double dialogWidth = 328;
static const double dialogWidth = 360;

static const double dialogHeight = 500;
static const double maxDialogHeight = 560;

static const double imageBorderRadius = 8.0;

Expand Down Expand Up @@ -37,4 +37,17 @@ class SendFileDialogStyle {
);

static const spaceBwInputBarAndButton = SizedBox(height: 8.0);

static const double maxHeightFilesListView = 320;

static const EdgeInsets paddingFilesListView = EdgeInsets.only(
top: 8.0,
);

static Color? listViewBackgroundColor(BuildContext context) =>
Theme.of(context).colorScheme.surface;

static const double listViewBorderRadius = 8.0;

static const paddingFileTile = EdgeInsets.only(bottom: 8.0);
}
133 changes: 102 additions & 31 deletions lib/pages/chat/send_file_dialog_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ import 'package:fluffychat/pages/chat/input_bar/input_bar.dart';
import 'package:fluffychat/pages/chat/send_file_dialog.dart';
import 'package:fluffychat/pages/image_viewer/image_viewer.dart';
import 'package:fluffychat/utils/interactive_viewer_gallery.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_file_extension.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/widgets/file_tile_widget.dart';
import 'package:fluffychat/widgets/hero_page_route.dart';
import 'package:flutter/material.dart';
import 'package:fluffychat/pages/chat/send_file_dialog_style.dart';

import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart';

class SendFileDialogView extends StatelessWidget {
final SendFileDialogController controller;
Expand All @@ -23,6 +26,9 @@ class SendFileDialogView extends StatelessWidget {
BorderRadius.circular(SendFileDialogStyle.dialogBorderRadius),
child: Container(
width: SendFileDialogStyle.dialogWidth,
constraints: const BoxConstraints(
maxHeight: SendFileDialogStyle.maxDialogHeight,
),
padding: const EdgeInsets.all(SendFileDialogStyle.dialogBorderRadius),
child: Column(
mainAxisSize: MainAxisSize.min,
Expand All @@ -33,42 +39,19 @@ class SendFileDialogView extends StatelessWidget {
Padding(
padding: SendFileDialogStyle.headerPadding,
child: Text(
L10n.of(context)!.sendImages(1),
controller.isSendMediaWithCaption
? L10n.of(context)!.sendImages(1)
: L10n.of(context)!
.sendFiles(controller.files.length),
style: Theme.of(context).textTheme.titleLarge,
),
),
],
),
const SizedBox(height: 16.0),
InkWell(
onTap: () {
Navigator.of(context, rootNavigator: PlatformInfos.isWeb)
.push(
HeroPageRoute(
builder: (context) {
return InteractiveViewerGallery(
itemBuilder: ImageViewer(
imageData: controller.widget.files.first.bytes,
),
);
},
),
);
},
child: SizedBox(
width: SendFileDialogStyle.imageSize,
height: SendFileDialogStyle.imageSize,
child: ClipRRect(
borderRadius: BorderRadius.circular(
SendFileDialogStyle.imageBorderRadius,
),
child: Image.memory(
controller.widget.files.first.bytes!,
fit: BoxFit.cover,
),
),
),
),
controller.isSendMediaWithCaption
? _MediaPageViewWidget(files: controller.files)
: _FilesListViewWidget(files: controller.files),
const SizedBox(height: 16.0),
InputBar(
maxLines: 5,
Expand Down Expand Up @@ -130,7 +113,9 @@ class SendFileDialogView extends StatelessWidget {
child: Text(
L10n.of(context)!.send,
style: Theme.of(context).textTheme.labelLarge?.copyWith(
color: Theme.of(context).colorScheme.onPrimary,
color: SendFileDialogStyle.listViewBackgroundColor(
context,
),
),
),
),
Expand All @@ -143,3 +128,89 @@ class SendFileDialogView extends StatelessWidget {
);
}
}

class _MediaPageViewWidget extends StatelessWidget {
const _MediaPageViewWidget({
required this.files,
});

final List<MatrixFile> files;

@override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
Navigator.of(context, rootNavigator: PlatformInfos.isWeb).push(
HeroPageRoute(
builder: (context) {
return InteractiveViewerGallery(
itemBuilder: ImageViewer(
imageData: files.first.bytes,
),
);
},
),
);
},
child: SizedBox(
width: SendFileDialogStyle.imageSize,
height: SendFileDialogStyle.imageSize,
child: ClipRRect(
borderRadius: BorderRadius.circular(
SendFileDialogStyle.imageBorderRadius,
),
child: files.first.bytes != null
? Image.memory(
files.first.bytes!,
fit: BoxFit.cover,
)
: const SizedBox.shrink(),
),
),
);
}
}

class _FilesListViewWidget extends StatelessWidget {
final List<MatrixFile> files;

const _FilesListViewWidget({
required this.files,
});

@override
Widget build(BuildContext context) {
return Container(
constraints: const BoxConstraints(
maxHeight: SendFileDialogStyle.maxHeightFilesListView,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(
SendFileDialogStyle.listViewBorderRadius,
),
color: SendFileDialogStyle.listViewBackgroundColor(context),
),
child: SingleChildScrollView(
child: ListView.builder(
itemCount: files.length,
shrinkWrap: true,
padding: SendFileDialogStyle.paddingFilesListView,
itemBuilder: (BuildContext context, int index) {
final file = files[index];
return Padding(
padding: SendFileDialogStyle.paddingFileTile,
child: FileTileWidget(
mimeType: file.mimeType,
filename: file.name,
fileType: file.fileExtension,
sizeString: file.sizeString,
backgroundColor:
SendFileDialogStyle.listViewBackgroundColor(context),
),
);
},
),
),
);
}
}
2 changes: 0 additions & 2 deletions lib/pages/chat_draft/draft_chat.dart
Original file line number Diff line number Diff line change
Expand Up @@ -299,15 +299,13 @@ class DraftChatController extends State<DraftChat>
);
}

@override
void sendFileOnWebAction(
BuildContext context, {
Room? room,
}) async {
final sendFileOnWebInteractor = getIt.get<SendFileOnWebInteractor>();
final result = await FilePicker.platform.pickFiles(
withData: true,
allowMultiple: true,
);
if (result == null || result.files.isEmpty) return;

Expand Down
Loading

0 comments on commit 5094a01

Please sign in to comment.