Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TW-230: change ux when create room #312

Merged
merged 3 commits into from
Jul 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions lib/config/routes.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import 'package:fluffychat/di/chat/chat_di.dart';
import 'package:fluffychat/di/contact/contact_di.dart';
import 'package:fluffychat/di/create_direct_chat/create_direct_chat_di.dart';
import 'package:fluffychat/pages/add_story/add_story.dart';
import 'package:fluffychat/pages/archive/archive.dart';
import 'package:fluffychat/pages/chat/chat.dart';
import 'package:fluffychat/pages/chat/empty_chat.dart';
import 'package:fluffychat/pages/chat_details/chat_details.dart';
import 'package:fluffychat/pages/chat_encryption_settings/chat_encryption_settings.dart';
import 'package:fluffychat/pages/chat_list/chat_list.dart';
Expand Down Expand Up @@ -33,6 +35,7 @@ import 'package:fluffychat/widgets/layouts/loading_view.dart';
import 'package:fluffychat/widgets/layouts/side_view_layout.dart';
import 'package:fluffychat/widgets/layouts/two_column_layout.dart';
import 'package:fluffychat/widgets/log_view.dart';
import 'package:fluffychat/widgets/vwidget_with_dependencies.dart';
import 'package:fluffychat/widgets/vwidget_with_dependency.dart';
import 'package:flutter/material.dart';
import 'package:vrouter/vrouter.dart';
Expand Down Expand Up @@ -170,6 +173,12 @@ class AppRoutes {
widget: const NewGroup(),
buildTransition: rightToLeftTransition,
),
VWidgetWithDependencies(
path: '/emptyChat',
dIs: [ChatScreenDi(), CreateDirectChatDi()],
widget: const EmptyChat(),
buildTransition: rightToLeftTransition,
),
]
),
],
Expand Down
13 changes: 13 additions & 0 deletions lib/di/create_direct_chat/create_direct_chat_di.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import 'package:fluffychat/di/base_di.dart';
import 'package:fluffychat/domain/usecase/create_direct_chat_interactor.dart';
import 'package:get_it/get_it.dart';

class CreateDirectChatDi extends BaseDI {
@override
String get scopeName => "Create direct chat";

@override
void setUp(GetIt get) {
get.registerSingleton<CreateDirectChatInteractor>(CreateDirectChatInteractor());
}
}
11 changes: 11 additions & 0 deletions lib/domain/app_state/direct_chat/create_direct_chat_failed.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import 'package:fluffychat/app_state/failure.dart';

class CreateDirectChatFailed extends Failure {

final dynamic exception;

const CreateDirectChatFailed({required this.exception});

@override
List<Object?> get props => [exception];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import 'package:fluffychat/app_state/success.dart';

class CreateDirectChatLoading extends Success {

const CreateDirectChatLoading();

@override
List<Object?> get props => [];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import 'package:fluffychat/app_state/success.dart';

class CreateDirectChatSuccess extends Success {
final String roomId;

const CreateDirectChatSuccess({required this.roomId});

@override
List<Object?> get props => [roomId];
}
34 changes: 34 additions & 0 deletions lib/domain/usecase/create_direct_chat_interactor.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import 'package:dartz/dartz.dart';
import 'package:fluffychat/app_state/failure.dart';
import 'package:fluffychat/app_state/success.dart';
import 'package:fluffychat/domain/app_state/direct_chat/create_direct_chat_failed.dart';
import 'package:fluffychat/domain/app_state/direct_chat/create_direct_chat_loading.dart';
import 'package:fluffychat/domain/app_state/direct_chat/create_direct_chat_success.dart';
import 'package:matrix/matrix.dart';

class CreateDirectChatInteractor {
Stream<Either<Failure, Success>> execute({
required String contactMxId,
required Client client,
List<StateEvent>? initialState,
bool? enableEncryption,
bool waitForSync = true,
Map<String, dynamic>? powerLevelContentOverride,
CreateRoomPreset? preset = CreateRoomPreset.trustedPrivateChat,
}) async* {
yield const Right(CreateDirectChatLoading());
try {
final roomId = await client.startDirectChat(
contactMxId,
initialState: initialState,
enableEncryption: enableEncryption,
waitForSync: waitForSync,
powerLevelContentOverride: powerLevelContentOverride,
preset: preset,
);
yield Right(CreateDirectChatSuccess(roomId: roomId));
} catch (e) {
yield Left(CreateDirectChatFailed(exception: e));
}
}
}
190 changes: 19 additions & 171 deletions lib/pages/chat/chat.dart
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
import 'dart:async';
import 'dart:io';
import 'dart:ui';
import 'package:file_picker/file_picker.dart';
import 'package:fluffychat/di/global/get_it_initializer.dart';
import 'package:fluffychat/domain/usecase/send_file_interactor.dart';
import 'package:fluffychat/domain/app_state/preview_file/download_file_for_preview_failure.dart';
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/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';
import 'package:fluffychat/domain/usecase/send_image_interactor.dart';
import 'package:fluffychat/domain/usecase/send_images_interactor.dart';
import 'package:fluffychat/pages/chat/chat_actions.dart';
import 'package:fluffychat/pages/forward/forward.dart';
import 'package:fluffychat/presentation/mixin/image_picker_mixin.dart';
import 'package:fluffychat/presentation/mixin/send_files_mixin.dart';
import 'package:fluffychat/utils/network_connection_service.dart';
import 'package:fluffychat/utils/permission_dialog.dart';
import 'package:fluffychat/utils/permission_service.dart';
Expand All @@ -30,7 +26,6 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:image_picker/image_picker.dart';
import 'package:linagora_design_flutter/images_picker/images_picker.dart' hide ImagePicker;
import 'package:matrix/matrix.dart';
import 'package:open_file/open_file.dart';
import 'package:path_provider/path_provider.dart';
Expand All @@ -49,7 +44,6 @@ import 'package:fluffychat/utils/matrix_sdk_extensions/ios_badge_client_extensio
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:wechat_camera_picker/wechat_camera_picker.dart';
import '../../utils/account_bundles.dart';
import '../../utils/localized_exception_extension.dart';
import '../../utils/matrix_sdk_extensions/matrix_file_extension.dart';
Expand All @@ -66,7 +60,7 @@ class Chat extends StatefulWidget {
ChatController createState() => ChatController();
}

class ChatController extends State<Chat> {
class ChatController extends State<Chat> with ImagePickerMixin, SendFilesMixin {
final NetworkConnectionService networkConnectionService = getIt.get<NetworkConnectionService>();

Room? room;
Expand All @@ -82,10 +76,6 @@ class ChatController extends State<Chat> {
final AutoScrollController scrollController = AutoScrollController();
final AutoScrollController forwardListController = AutoScrollController();

final ImagePickerGridController imagePickerController = ImagePickerGridController();

final numberSelectedImagesNotifier = ValueNotifier<int>(0);

FocusNode inputFocus = FocusNode();

Timer? typingCoolDown;
Expand Down Expand Up @@ -253,18 +243,12 @@ class ChatController extends State<Chat> {
}
}

void _registerListenerForSelectedImagesChanged() {
imagePickerController.addListener(() {
numberSelectedImagesNotifier.value = imagePickerController.selectedAssets.length;
});
}

@override
void initState() {
scrollController.addListener(_updateScrollController);
inputFocus.addListener(_inputFocusListener);
_loadDraft();
_registerListenerForSelectedImagesChanged();
listenToSelectionInImagePicker();
super.initState();
}

Expand All @@ -273,6 +257,21 @@ class ChatController extends State<Chat> {
setState(() {});
}

bool isContactsLastPage() {
final previousPath = VRouter.of(context).previousPath;
return previousPath?.endsWith('newprivatechat') == true
|| previousPath?.endsWith('contactsTab') == true
|| previousPath?.endsWith('emptyChat') == true;
}
Comment on lines +260 to +265
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you check if previousPath is null please ?

WDYT

Suggested change
bool isContactsLastPage() {
final previousPath = VRouter.of(context).previousPath;
return previousPath?.endsWith('newprivatechat') == true
|| previousPath?.endsWith('contactsTab') == true
|| previousPath?.endsWith('emptyChat') == true;
}
bool isContactsLastPage() {
final previousPath = VRouter.of(context).previousPath;
if (previousPath == null) return false;
return previousPath.endsWith('newprivatechat')
|| previousPath.endsWith('contactsTab')
|| previousPath.endsWith('emptyChat');
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, no need, because previousPath is nullable, with the null safety call ?. https://dart.dev/codelabs/null-safety


void backToPreviousPage() {
if (isContactsLastPage()) {
VRouter.of(context).historyBack();
} else {
VRouter.of(context).pop();
}
}

Future<bool> getTimeline() async {
if (timeline == null) {
await Matrix.of(context).client.roomsLoading;
Expand Down Expand Up @@ -389,64 +388,6 @@ class ChatController extends State<Chat> {
});
}

void sendFileAction() async {
final sendFileInteractor = getIt.get<SendFileInteractor>();
Navigator.pop(context);
final result = await FilePicker.platform.pickFiles(
withData: true,
);
if (result == null && result?.files.isEmpty == true) return;

sendFileInteractor.execute(room: room!, filePickerResult: result!);
}
hoangdat marked this conversation as resolved.
Show resolved Hide resolved

void sendImage() {
final assetEntity = imagePickerController.selectedAssets.first;
final sendImageInteractor = getIt.get<SendImageInteractor>();
if (assetEntity.asset.type == AssetType.image) {
sendImageInteractor.execute(room: room!, entity: assetEntity.asset);
imagePickerController.clearAssetCounter();
numberSelectedImagesNotifier.value = 0;
}
}

Future<void> sendImages() async {
final selectedAssets = imagePickerController.sortedSelectedAssets;
final sendImagesInteractor = getIt.get<SendImagesInteractor>();
sendImagesInteractor.execute(
room: room!,
entities: selectedAssets
.map<AssetEntity>((entity) => entity.asset)
.toList()
);

imagePickerController.clearAssetCounter();
numberSelectedImagesNotifier.value = 0;
}
hoangdat marked this conversation as resolved.
Show resolved Hide resolved

void openCameraAction() async {
// Make sure the textfield is unfocused before opening the camera
FocusScope.of(context).requestFocus(FocusNode());
final file = await ImagePicker().pickImage(source: ImageSource.camera);
if (file == null) return;
final bytes = await file.readAsBytes();
await showDialog(
context: context,
useRootNavigator: false,
builder: (c) => SendFileDialog(
files: [
MatrixImageFile(
bytes: bytes,
name: file.path,
)
],
room: room!,
),
);
}
hoangdat marked this conversation as resolved.
Show resolved Hide resolved



void onFileTapped({required Event event}) async {
final permissionHandler = PermissionHandlerService();
final storagePermissionStatus = await permissionHandler.storagePermissionStatus;
Expand Down Expand Up @@ -488,7 +429,6 @@ class ChatController extends State<Chat> {
case PermissionStatus.provisional:
break;
}

}


Expand Down Expand Up @@ -1090,24 +1030,6 @@ class ChatController extends State<Chat> {
FocusScope.of(context).requestFocus(inputFocus);
}

void onAddPopupMenuButtonSelected(String choice) {
if (choice == 'file') {
sendFileAction();
}
if (choice == 'camera') {
openCameraAction();
}
if (choice == 'camera-video') {
openVideoCameraAction();
}
if (choice == 'sticker') {
sendStickerAction();
}
if (choice == 'location') {
sendLocationAction();
}
}

unpinEvent(String eventId) async {
final response = await showOkCancelAlertDialog(
context: context,
Expand Down Expand Up @@ -1261,80 +1183,6 @@ class ChatController extends State<Chat> {
editEvent = null;
});

Future<PermissionStatus>? getCurrentPhotoPermission() {
return PermissionHandlerService().requestPermissionForPhotoActions();
}

Future<PermissionStatus>? getCurrentCameraPermission() {
return PermissionHandlerService().requestPermissionForCameraActions();
}

Future<void> goToSettings() async {
final result = await showDialog<bool?>(
context: context,
useRootNavigator: false,
builder: (c) => PermissionDialog(
permission: Permission.camera,
explainTextRequestPermission: RichText(
text: TextSpan(
text: '${L10n.of(context)!.tapToAllowAccessToYourCamera} ',
style: Theme.of(context).textTheme.titleSmall,
children: <TextSpan>[
TextSpan(text: '${L10n.of(context)!.twake}.', style: Theme.of(context).textTheme.titleSmall!.copyWith(
fontWeight: FontWeight.bold,
)),
],
),
),
icon: const Icon(Icons.camera_alt),
onAcceptButton: () => PermissionHandlerService().goToSettingsForPermissionActions(),
),
);

if (result == true) {
Navigator.pop(context);
}
}

void imagePickAction() async {
Navigator.pop(context);
final assetEntity = await CameraPicker.pickFromCamera(
context,
locale: window.locale,
);
if (assetEntity != null && assetEntity.type == AssetType.image) {
final sendImageInteractor = getIt.get<SendImageInteractor>();
sendImageInteractor.execute(room: room!, entity: assetEntity);
}
}

void removeAllImageSelected() {
imagePickerController.clearAssetCounter();
numberSelectedImagesNotifier.value = 0;
}

List<ChatActions> get listChatActions => [
ChatActions.gallery,
ChatActions.documents,
ChatActions.location,
ChatActions.contact
];


void onClickItemAction(ChatActions action) async {
switch (action) {
case ChatActions.gallery:
break;
case ChatActions.documents:
sendFileAction();
break;
case ChatActions.location:
break;
case ChatActions.contact:
break;
}
}

@override
Widget build(BuildContext context) => ChatView(this);
}
Expand Down
Loading
Loading