diff --git a/.github/workflows/main.yml b/.github/workflows/build.yml similarity index 52% rename from .github/workflows/main.yml rename to .github/workflows/build.yml index ca43c066..e814cb60 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/build.yml @@ -5,6 +5,9 @@ on: branches: - master - feature/new-ui + release: + types: + - created jobs: build_and_deploy_ios: @@ -24,19 +27,6 @@ jobs: run: | cd example flutter pub get - - name: Coverage fix - run: | - file=test/coverage_helper_test.dart - echo "// Helper file to make coverage work for all dart files\n" > $file - echo "// ignore_for_file: unused_import" >> $file - find lib -name '*.dart' | grep -e '[^g]\.dart' | grep -v '_html.dart' | cut -c4- | awk -v package=stream_chat_flutter '{printf "import '\''package:%s%s'\'';\n", package, $1}' >> $file - echo "" >> $file - echo "void main(){}" >> $file - cat $file - - name: Run tests - run: flutter test --coverage - - name: Codecov - run: bash <(curl -s https://codecov.io/bash) -c -t ${{ secrets.CODECOV_TOKEN }} -f coverage/lcov.info -F flutter_tool - name: Build and release env: MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} @@ -60,19 +50,6 @@ jobs: - run: | cd example flutter pub get - - name: Coverage fix - run: | - file=test/coverage_helper_test.dart - echo "// Helper file to make coverage work for all dart files\n" > $file - echo "// ignore_for_file: unused_import" >> $file - find lib -name '*.dart' | grep -e '[^g]\.dart' | grep -v '_html.dart' | cut -c4- | awk -v package=stream_chat_flutter '{printf "import '\''package:%s%s'\'';\n", package, $1}' >> $file - echo "" >> $file - echo "void main(){}" >> $file - cat $file - - name: Run tests - run: flutter test --coverage - - name: Codecov - run: bash <(curl -s https://codecov.io/bash) -c -t ${{ secrets.CODECOV_TOKEN }} -f coverage/lcov.info -F flutter_tool - name: Build run: | cd example diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..a8e87c58 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,28 @@ +name: Test + +on: + pull_request: +jobs: + test: + runs-on: [ubuntu-latest] + steps: + - uses: actions/checkout@v2 + - name: Flutter action + uses: subosito/flutter-action@v1.3.2 + with: + channel: 'stable' + - name: Get dependencies + run: flutter pub get + - name: Coverage fix + run: | + file=test/coverage_helper_test.dart + echo "// Helper file to make coverage work for all dart files\n" > $file + echo "// ignore_for_file: unused_import" >> $file + find lib -name '*.dart' | grep -e '[^g]\.dart' | grep -v '_html.dart' | cut -c4- | awk -v package=stream_chat_flutter '{printf "import '\''package:%s%s'\'';\n", package, $1}' >> $file + echo "" >> $file + echo "void main(){}" >> $file + cat $file + - name: Run tests + run: flutter test --coverage + - name: Codecov + run: bash <(curl -s https://codecov.io/bash) -c -t ${{ secrets.CODECOV_TOKEN }} -f coverage/lcov.info -F flutter_tool diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 5745f779..7bdbfd5d 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1,9 +1,9 @@ import 'dart:async'; -import 'dart:io'; import 'dart:math'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; import 'package:http_parser/http_parser.dart'; @@ -17,7 +17,7 @@ import 'package:stream_chat_flutter/src/user_avatar.dart'; import '../stream_chat_flutter.dart'; import 'stream_channel.dart'; -typedef FileUploader = Future Function(File, Channel); +typedef FileUploader = Future Function(PlatformFile, Channel); typedef AttachmentThumbnailBuilder = Widget Function( BuildContext, _SendingAttachment, @@ -777,8 +777,8 @@ class MessageInputState extends State { case 'image': case 'giphy': return attachment.file != null - ? Image.file( - attachment.file, + ? Image.memory( + attachment.file.bytes, fit: BoxFit.cover, ) : Image.network( @@ -888,22 +888,24 @@ class MessageInputState extends State { Navigator.pop(context); }, ), - ListTile( - leading: Icon(Icons.camera_alt), - title: Text('Photo from camera'), - onTap: () { - pickFile(DefaultAttachmentTypes.image, true); - Navigator.pop(context); - }, - ), - ListTile( - leading: Icon(Icons.videocam), - title: Text('Video from camera'), - onTap: () { - pickFile(DefaultAttachmentTypes.video, true); - Navigator.pop(context); - }, - ), + if (!kIsWeb) + ListTile( + leading: Icon(Icons.camera_alt), + title: Text('Photo from camera'), + onTap: () { + pickFile(DefaultAttachmentTypes.image, true); + Navigator.pop(context); + }, + ), + if (!kIsWeb) + ListTile( + leading: Icon(Icons.videocam), + title: Text('Video from camera'), + onTap: () { + pickFile(DefaultAttachmentTypes.video, true); + Navigator.pop(context); + }, + ), ListTile( leading: Icon(Icons.insert_drive_file), title: Text('Upload a file'), @@ -935,7 +937,7 @@ class MessageInputState extends State { _inputEnabled = false; }); - File file; + PlatformFile file; String attachmentType; if (fileType == DefaultAttachmentTypes.image) { @@ -953,7 +955,11 @@ class MessageInputState extends State { } else if (fileType == DefaultAttachmentTypes.video) { pickedFile = await _imagePicker.getVideo(source: ImageSource.camera); } - file = File(pickedFile.path); + final bytes = await pickedFile.readAsBytes(); + file = PlatformFile( + path: pickedFile.path, + bytes: bytes, + ); } else { FileType type; if (fileType == DefaultAttachmentTypes.image) { @@ -963,9 +969,13 @@ class MessageInputState extends State { } else if (fileType == DefaultAttachmentTypes.file) { type = FileType.any; } - final res = await FilePicker.platform.pickFiles(type: type); + final res = await FilePicker.platform.pickFiles( + type: type, + withData: true, + ); if (res?.files?.isNotEmpty == true) { - file = File(res.files.first.path); + file = res.files.single; + print('file.bytes?.length: ${file.bytes?.length}'); } } @@ -978,11 +988,10 @@ class MessageInputState extends State { } final channel = StreamChannel.of(context).channel; - final attachment = _SendingAttachment( file: file, attachment: Attachment( - localUri: file.uri, + localUri: file.path != null ? Uri.parse(file.path) : null, type: attachmentType, ), ); @@ -1009,7 +1018,7 @@ class MessageInputState extends State { } Future _uploadAttachment( - File file, + PlatformFile file, DefaultAttachmentTypes type, Channel channel, ) async { @@ -1030,9 +1039,9 @@ class MessageInputState extends State { return url; } - Future _uploadImage(File file, Channel channel) async { - final filename = file.path.split('/').last; - final bytes = await file.readAsBytes(); + Future _uploadImage(PlatformFile file, Channel channel) async { + final filename = file.name ?? file.path?.split('/')?.last; + final bytes = file.bytes; final res = await channel.sendImage( MultipartFile.fromBytes( bytes, @@ -1043,9 +1052,9 @@ class MessageInputState extends State { return res.file; } - Future _uploadFile(File file, Channel channel) async { - final filename = file.path.split('/').last; - final bytes = await file.readAsBytes(); + Future _uploadFile(PlatformFile file, Channel channel) async { + final filename = file.name ?? file.path?.split('/')?.last; + final bytes = file.bytes; final res = await channel.sendFile( MultipartFile.fromBytes( bytes, @@ -1209,34 +1218,36 @@ class MessageInputState extends State { void initState() { super.initState(); - _keyboardListener = KeyboardVisibility.onChange.listen((visible) { - if (visible) { - if (_commandsOverlay != null) { - if (textEditingController.text.startsWith('/')) { - WidgetsBinding.instance.addPostFrameCallback((_) { - _commandsOverlay = _buildCommandsOverlayEntry(); - Overlay.of(context).insert(_commandsOverlay); - }); + if (!kIsWeb) { + _keyboardListener = KeyboardVisibility.onChange.listen((visible) { + if (visible) { + if (_commandsOverlay != null) { + if (textEditingController.text.startsWith('/')) { + WidgetsBinding.instance.addPostFrameCallback((_) { + _commandsOverlay = _buildCommandsOverlayEntry(); + Overlay.of(context).insert(_commandsOverlay); + }); + } } - } - if (_mentionsOverlay != null) { - if (textEditingController.text.contains('@')) { - WidgetsBinding.instance.addPostFrameCallback((_) { - _mentionsOverlay = _buildCommandsOverlayEntry(); - Overlay.of(context).insert(_mentionsOverlay); - }); + if (_mentionsOverlay != null) { + if (textEditingController.text.contains('@')) { + WidgetsBinding.instance.addPostFrameCallback((_) { + _mentionsOverlay = _buildCommandsOverlayEntry(); + Overlay.of(context).insert(_mentionsOverlay); + }); + } + } + } else { + if (_commandsOverlay != null) { + _commandsOverlay.remove(); + } + if (_mentionsOverlay != null) { + _mentionsOverlay.remove(); } } - } else { - if (_commandsOverlay != null) { - _commandsOverlay.remove(); - } - if (_mentionsOverlay != null) { - _mentionsOverlay.remove(); - } - } - }); + }); + } textEditingController = widget.textEditingController ?? TextEditingController(); @@ -1263,7 +1274,7 @@ class MessageInputState extends State { void dispose() { _commandsOverlay?.remove(); _mentionsOverlay?.remove(); - _keyboardListener.cancel(); + _keyboardListener?.cancel(); super.dispose(); } @@ -1279,7 +1290,7 @@ class MessageInputState extends State { } class _SendingAttachment { - File file; + PlatformFile file; Attachment attachment; bool uploaded;