Skip to content
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
7 changes: 6 additions & 1 deletion sama_chat_client/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:launchMode="singleTask"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
Expand All @@ -37,6 +37,11 @@
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
Expand Down
2 changes: 2 additions & 0 deletions sama_chat_client/ios/Share Extension/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
<true/>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
<integer>100</integer>
</dict>
</dict>
<key>NSExtensionMainStoryboard</key>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class MediaSenderBloc extends Bloc<MediaSenderEvent, MediaSenderState> {
_onMessageChanged,
);

on<_AddFiles>(
on<AddFiles>(
_onFilesAdded,
);

Expand All @@ -55,8 +55,6 @@ class MediaSenderBloc extends Bloc<MediaSenderEvent, MediaSenderState> {
on<CancelSelection>(
_onCancelSelection,
);

_pickMedia();
}

FutureOr<void> _onPickFiles(
Expand All @@ -65,8 +63,7 @@ class MediaSenderBloc extends Bloc<MediaSenderEvent, MediaSenderState> {
_pickMedia();
}

FutureOr<void> _onFilesAdded(
_AddFiles event, Emitter<MediaSenderState> emit) {
FutureOr<void> _onFilesAdded(AddFiles event, Emitter<MediaSenderState> emit) {
emit(state.copyWith(status: MediaSelectorStatus.mediaSelected));
if (event.error?.isNotEmpty ?? false) {
emit(state.copyWith(error: event.error));
Expand Down Expand Up @@ -191,16 +188,16 @@ class MediaSenderBloc extends Bloc<MediaSenderEvent, MediaSenderState> {
.then((result) {
var files = result?.files;
if (files?.isEmpty ?? true) {
add(const _AddFiles([]));
add(const AddFiles([]));
} else {
var files = List<File>.from(result?.files
.map((platformFile) => File(platformFile.path!))
.toList() ??
[]);
add(_AddFiles(files));
add(AddFiles(files));
}
}).catchError((onError) {
add(const _AddFiles([],
add(const AddFiles([],
error: 'Please allow permission access to Gallery'));
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ class MediaSenderEvent extends Equatable {
List<Object> get props => [];
}

final class _AddFiles extends MediaSenderEvent {
final class AddFiles extends MediaSenderEvent {
final List<File> selectedFiles;
final String? error;

const _AddFiles(this.selectedFiles, {this.error});
const AddFiles(this.selectedFiles, {this.error});
}

final class PickMoreFiles extends MediaSenderEvent {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,11 @@ class ConversationPage extends StatelessWidget {
},
child: ConnectionChecker(
child: MessageInput(
sharedText: context
sharedMessage: context
.read<SharingIntentBloc>()
.state
.sharedFiles
.firstOrNull
?.path)),
.firstOrNull)),
)
: const MessageInput()
: const SelectInput())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,23 @@ import 'package:path/path.dart';
import '../../../db/models/conversation_model.dart';
import '../../../db/models/message_model.dart';
import '../../../repository/messages/messages_repository.dart';
import '../../../shared/sharing/bloc/sharing_intent_bloc.dart';
import '../../../shared/ui/colors.dart';
import '../../../shared/utils/date_utils.dart';
import '../../../shared/utils/media_utils.dart';
import '../bloc/media_sender/media_sender_bloc.dart';

class MediaSender extends StatelessWidget {
final MessageModel? replyMessage;
final String? path;

const MediaSender(this.replyMessage, {super.key});
const MediaSender(this.replyMessage, this.path, {super.key});

static Widget create({
Key? key,
required ConversationModel currentConversation,
required MessageModel? replyMessage,
required String? path,
}) {
return BlocProvider<MediaSenderBloc>(
create: (context) => MediaSenderBloc(
Expand All @@ -31,18 +34,28 @@ class MediaSender extends StatelessWidget {
RepositoryProvider.of<MessagesRepository>(context)),
child: MediaSender(
replyMessage,
path,
key: key,
),
);
}

@override
Widget build(BuildContext context) {
if (path != null) {
BlocProvider.of<MediaSenderBloc>(context).add(AddFiles([File(path!)]));
} else {
BlocProvider.of<MediaSenderBloc>(context).add(const PickMoreFiles());
}
return BlocListener<MediaSenderBloc, MediaSenderState>(
listener: (context, state) {
if (state.status == MediaSelectorStatus.processingFinished ||
state.status == MediaSelectorStatus.canceled) {
context.pop();
if (context.read<SharingIntentBloc>().state.status ==
SharingIntentStatus.processing) {
context.read<SharingIntentBloc>().add(SharingIntentCompleted());
}
}
},
child: BlocBuilder<MediaSenderBloc, MediaSenderState>(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:receive_sharing_intent/receive_sharing_intent.dart';

import '../../../shared/connection/view/connection_checker.dart';
import '../../../shared/ui/colors.dart';
Expand All @@ -11,9 +13,9 @@ import '../widgets/header_input_box.dart';
import 'media_sender.dart';

class MessageInput extends StatefulWidget {
final String? sharedText;
final SharedMediaFile? sharedMessage;

const MessageInput({super.key, this.sharedText});
const MessageInput({super.key, this.sharedMessage});

@override
State<StatefulWidget> createState() {
Expand All @@ -23,17 +25,33 @@ class MessageInput extends StatefulWidget {

class _MessageInputState extends State<MessageInput> {
late final TextEditingController textEditingController =
TextEditingController(text: widget.sharedText);
TextEditingController(
text: widget.sharedMessage?.type == SharedMediaType.text ||
widget.sharedMessage?.type == SharedMediaType.url
? widget.sharedMessage?.path
: null);

final FocusNode showFocusNode = FocusNode();
BuildContext? dialogContext;

@override
void initState() {
super.initState();
if (widget.sharedMessage?.type == SharedMediaType.image) {
WidgetsBinding.instance.addPostFrameCallback((_) {
showMedia(widget.sharedMessage?.path);
});
}
}

@override
Widget build(BuildContext context) {
var showReply = false;
var showEdit = false;
if (widget.sharedText != null) {
if (widget.sharedMessage?.type == SharedMediaType.text ||
widget.sharedMessage?.type == SharedMediaType.url) {
BlocProvider.of<SendMessageBloc>(context)
.add(TextMessageChanged(widget.sharedText!));
.add(TextMessageChanged(widget.sharedMessage!.path));
}
return MultiBlocListener(
listeners: [
Expand All @@ -57,7 +75,7 @@ class _MessageInputState extends State<MessageInput> {
return (previous.draftMessage != current.draftMessage ||
previous.replyMessage != current.replyMessage ||
previous.editMessage != current.editMessage) &&
widget.sharedText == null;
widget.sharedMessage == null;
},
listener: (context, state) {
showReply = state.replyMessage != null;
Expand Down Expand Up @@ -121,28 +139,7 @@ class _MessageInputState extends State<MessageInput> {
icon: const Icon(Icons.attach_file_outlined),
color: dullGray,
onPressed: () {
connectionChecker(
context,
() => showDialog(
barrierDismissible: false,
context: context,
builder: (context) {
return AlertDialog(
contentPadding: const EdgeInsets.symmetric(
vertical: 8.0, horizontal: 10.0),
actionsPadding: EdgeInsets.zero,
buttonPadding: EdgeInsets.zero,
content: SizedBox(
width: double.maxFinite,
child: MediaSender.create(
currentConversation: rootContext
.watch<SendMessageBloc>()
.currentConversation,
replyMessage: state.replyMessage),
),
);
},
));
connectionChecker(context, () => showMedia());
},
),
Flexible(
Expand Down Expand Up @@ -195,8 +192,36 @@ class _MessageInputState extends State<MessageInput> {
}
}

showMedia([String? path]) {
showDialog(
barrierDismissible: false,
context: context,
builder: (ctx) {
dialogContext = ctx;
return AlertDialog(
contentPadding:
const EdgeInsets.symmetric(vertical: 8.0, horizontal: 10.0),
actionsPadding: EdgeInsets.zero,
buttonPadding: EdgeInsets.zero,
content: SizedBox(
width: double.maxFinite,
child: MediaSender.create(
currentConversation:
context.watch<SendMessageBloc>().currentConversation,
replyMessage: BlocProvider.of<SendMessageBloc>(context)
.state
.replyMessage,
path: path),
));
},
).then((result) async {
dialogContext = null;
});
}

@override
void dispose() {
if (dialogContext != null && dialogContext!.mounted) dialogContext!.pop();
showFocusNode.dispose();
super.dispose();
}
Expand Down