-
Notifications
You must be signed in to change notification settings - Fork 14
feat: media upload ui #721
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
Changes from all commits
d5ae568
68302c5
2bb5f30
e2ecbda
43421d1
e061b15
38be013
b19261d
13ac656
d993f24
36680f2
f089764
aa120b1
561a675
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,119 @@ | ||
| import 'dart:async'; | ||
| import 'package:flutter_riverpod/flutter_riverpod.dart'; | ||
| import 'package:logging/logging.dart'; | ||
| import 'package:whitenoise/domain/services/draft_message_service.dart'; | ||
| import 'package:whitenoise/domain/services/image_picker_service.dart'; | ||
| import 'package:whitenoise/ui/chat/states/chat_input_state.dart'; | ||
|
|
||
| class ChatInputNotifier extends FamilyNotifier<ChatInputState, String> { | ||
| ChatInputNotifier({ | ||
| ImagePickerService? imagePickerService, | ||
| DraftMessageService? draftMessageService, | ||
| Duration draftSaveDelay = const Duration(milliseconds: 500), | ||
| }) : _imagePickerService = imagePickerService ?? ImagePickerService(), | ||
| _draftMessageService = draftMessageService ?? DraftMessageService(), | ||
| _draftSaveDelay = draftSaveDelay; | ||
|
|
||
| static final _logger = Logger('ChatInputNotifier'); | ||
| late final String _groupId; | ||
| final ImagePickerService _imagePickerService; | ||
| final DraftMessageService _draftMessageService; | ||
| final Duration _draftSaveDelay; | ||
| Timer? _draftSaveTimer; | ||
|
|
||
| @override | ||
| ChatInputState build(String groupId) { | ||
| _groupId = groupId; | ||
| ref.onDispose(() { | ||
| _draftSaveTimer?.cancel(); | ||
| }); | ||
| return const ChatInputState(); | ||
| } | ||
|
|
||
| Future<String?> loadDraft() async { | ||
| state = state.copyWith(isLoadingDraft: true); | ||
| try { | ||
| final draft = await _draftMessageService.loadDraft(chatId: _groupId); | ||
| return draft; | ||
| } finally { | ||
| state = state.copyWith(isLoadingDraft: false); | ||
| } | ||
| } | ||
|
|
||
| void scheduleDraftSave(String text) { | ||
| _draftSaveTimer?.cancel(); | ||
| _draftSaveTimer = Timer( | ||
| _draftSaveDelay, | ||
| () => _saveDraft(text), | ||
| ); | ||
| } | ||
|
|
||
| Future<void> saveDraftImmediately(String text) async { | ||
| _draftSaveTimer?.cancel(); | ||
| await _saveDraft(text); | ||
| } | ||
|
|
||
| Future<void> _saveDraft(String text) async { | ||
| await _draftMessageService.saveDraft(chatId: _groupId, message: text); | ||
| } | ||
josefinalliende marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| void hideMediaSelector() { | ||
| state = state.copyWith(showMediaSelector: false); | ||
| } | ||
|
|
||
| void toggleMediaSelector() { | ||
| state = state.copyWith(showMediaSelector: !state.showMediaSelector); | ||
| } | ||
|
|
||
| Future<void> handleImagesSelected() async { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider adding error handling incase something goes wrong
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is in the builder if the UI, if an error happens, the image is not shown. Already checked that case in my iphone by hardcoding local paths that don't exist and it works fine
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But now giving a second thought, something else could go wrong before getting to the widget right? I will add error handling here. Thanks
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in c28a784 👍🏻 |
||
| try { | ||
| final imagePaths = await _imagePickerService.pickMultipleImages(); | ||
| if (imagePaths.isNotEmpty) { | ||
| state = state.copyWith( | ||
| showMediaSelector: false, | ||
| selectedImages: [...state.selectedImages, ...imagePaths], | ||
| ); | ||
| } else { | ||
| state = state.copyWith(showMediaSelector: false); | ||
| } | ||
| } catch (e) { | ||
| _logger.warning('Failed to select images for group $_groupId', e); | ||
| state = state.copyWith(showMediaSelector: false); | ||
| } | ||
| } | ||
|
|
||
| void removeImage(int index) { | ||
| if (index < 0 || index >= state.selectedImages.length) { | ||
| _logger.warning('Invalid image index: $index'); | ||
| return; | ||
| } | ||
| final updatedImages = List<String>.from(state.selectedImages); | ||
| updatedImages.removeAt(index); | ||
| state = state.copyWith(selectedImages: updatedImages); | ||
| } | ||
|
|
||
| void setSingleLineHeight(double height) { | ||
| if (state.singleLineHeight != height) { | ||
| state = state.copyWith(singleLineHeight: height); | ||
| } | ||
| } | ||
|
|
||
| void setPreviousEditingMessageContent(String? content) { | ||
| state = state.copyWith(previousEditingMessageContent: content); | ||
| } | ||
|
|
||
| Future<void> clear() async { | ||
| _draftSaveTimer?.cancel(); | ||
| await _draftMessageService.clearDraft(chatId: _groupId); | ||
| state = state.copyWith( | ||
| showMediaSelector: false, | ||
| isLoadingDraft: false, | ||
| previousEditingMessageContent: null, | ||
| selectedImages: [], | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| final chatInputProvider = NotifierProvider.family<ChatInputNotifier, ChatInputState, String>( | ||
| ChatInputNotifier.new, | ||
| ); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import 'package:freezed_annotation/freezed_annotation.dart'; | ||
|
|
||
| part 'chat_input_state.freezed.dart'; | ||
|
|
||
| @freezed | ||
| class ChatInputState with _$ChatInputState { | ||
| const factory ChatInputState({ | ||
| @Default(false) bool isLoadingDraft, | ||
| @Default(false) bool showMediaSelector, | ||
| @Default([]) List<String> selectedImages, | ||
| double? singleLineHeight, | ||
| String? previousEditingMessageContent, | ||
| }) = _ChatInputState; | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.