diff --git a/lib/ui/tiles/conversation_message_tile.dart b/lib/ui/tiles/conversation_message_tile.dart index deb5ac3..208511d 100644 --- a/lib/ui/tiles/conversation_message_tile.dart +++ b/lib/ui/tiles/conversation_message_tile.dart @@ -1,3 +1,4 @@ +import 'package:clipboard/clipboard.dart'; import 'package:comunic/models/conversation.dart'; import 'package:comunic/models/conversation_message.dart'; import 'package:comunic/models/user.dart'; @@ -13,7 +14,12 @@ import 'package:flutter/material.dart'; /// /// @author Pierre HUBERT -enum _MenuChoices { DELETE, REQUEST_UPDATE_CONTENT } +enum _MenuChoices { + COPY_URL, + COPY_MESSAGE, + DELETE, + REQUEST_UPDATE_CONTENT +} typedef OnRequestMessageUpdate = void Function(ConversationMessage); typedef OnRequestMessageDelete = void Function(ConversationMessage); @@ -60,6 +66,18 @@ class ConversationMessageTile extends StatelessWidget { width: 35.0, ), itemBuilder: (c) => [ + + PopupMenuItem( + enabled: (message.message?.content ?? "") != "", + value: _MenuChoices.COPY_MESSAGE, + child: Text(tr("Copy message")), + ), + + PopupMenuItem( + enabled: message.file != null, + value: _MenuChoices.COPY_URL, + child: Text(tr("Copy URL")), + ), // Update message content PopupMenuItem( enabled: message.isOwner, @@ -249,6 +267,14 @@ class ConversationMessageTile extends StatelessWidget { /// Process menu choice void _menuOptionSelected(_MenuChoices value) { switch (value) { + case _MenuChoices.COPY_MESSAGE: + FlutterClipboard.copy(message.message.content); + break; + + case _MenuChoices.COPY_URL: + FlutterClipboard.copy(message.file.url); + break; + case _MenuChoices.REQUEST_UPDATE_CONTENT: onRequestMessageUpdate(message); break; diff --git a/lib/ui/widgets/audio_player_widget.dart b/lib/ui/widgets/audio_player_widget.dart deleted file mode 100644 index 11a86da..0000000 --- a/lib/ui/widgets/audio_player_widget.dart +++ /dev/null @@ -1,135 +0,0 @@ -import 'dart:io'; - -import 'package:audioplayers/audioplayers.dart'; -import 'package:comunic/utils/date_utils.dart'; -import 'package:flutter/material.dart'; - -/// Audio player widget -/// -/// @author Pierre Hubert - -class AudioPlayerWidget extends StatefulWidget { - final File file; - - const AudioPlayerWidget(this.file); - - @override - _AudioPlayerWidgetState createState() => _AudioPlayerWidgetState(); -} - -class _AudioPlayerWidgetState extends State { - AudioPlayer _player; - - Duration _mediaDuration; - Duration _mediaPosition; - - double get _max => _mediaDuration?.inMilliseconds?.toDouble() ?? 0.0; - - double get _value => _mediaPosition?.inMilliseconds?.toDouble() ?? 0.0; - - bool get _playing => - _player != null && _player.state == AudioPlayerState.PLAYING; - - @override - void dispose() { - super.dispose(); - - if (_player != null) _player.dispose(); - } - - @override - Widget build(BuildContext context) { - return Material( - textStyle: TextStyle(color: Colors.white), - color: Colors.transparent, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Spacer(), - Icon(Icons.audiotrack, color: Colors.white), - Spacer(), - Slider( - value: _value, - onChanged: (newValue) => - _player.seek(Duration(milliseconds: newValue.toInt())), - max: _max, - activeColor: Colors.white, - min: 0, - ), - Spacer(), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Spacer(), - Text(formatDuration(_mediaPosition ?? Duration())), - Spacer(), - _AudioButton( - icon: Icons.play_arrow, onTap: _play, visible: !_playing), - _AudioButton(icon: Icons.pause, onTap: _pause, visible: _playing), - _AudioButton(icon: Icons.stop, onTap: _stop, visible: _playing), - Spacer(), - _playing ? Container() : Text(formatDuration(_mediaDuration ?? Duration())), - Spacer(), - ], - ), - Spacer(), - ], - ), - ); - } - - void _play() async { - if (_player == null) { - _player = AudioPlayer(); - - _player.onDurationChanged.listen((newDuration) { - setState(() => _mediaDuration = newDuration); - }); - - _player.onAudioPositionChanged.listen((newDuration) { - setState(() => _mediaPosition = newDuration); - }); - - _player.onPlayerStateChanged.listen((event) => setState(() {})); - - _player.onSeekComplete.listen((event) => setState(() {})); - } - - if (_player.state != AudioPlayerState.PAUSED) - _player.play(widget.file.absolute.path, isLocal: true); - else - _player.resume(); - } - - void _pause() async { - _player.pause(); - } - - void _stop() { - _player.stop(); - _player.seek(Duration()); - } -} - -class _AudioButton extends StatelessWidget { - final IconData icon; - final void Function() onTap; - final bool visible; - - const _AudioButton({ - Key key, - @required this.icon, - @required this.onTap, - @required this.visible, - }) : assert(icon != null), - assert(onTap != null), - assert(visible != null), - super(key: key); - - @override - Widget build(BuildContext context) { - if (!visible) return Container(); - - return IconButton(icon: Icon(icon, color: Colors.white), onPressed: onTap); - } -} diff --git a/lib/ui/widgets/conversation_file_tile.dart b/lib/ui/widgets/conversation_file_tile.dart index 6b5a0a0..c2eb2a3 100644 --- a/lib/ui/widgets/conversation_file_tile.dart +++ b/lib/ui/widgets/conversation_file_tile.dart @@ -3,6 +3,7 @@ /// @author Pierre Hubert import 'package:comunic/models/conversation_message.dart'; import 'package:comunic/ui/widgets/network_image_widget.dart'; +import 'package:filesize/filesize.dart'; import 'package:flutter/material.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -60,6 +61,11 @@ class _ConversationFileWidgetState extends State { Icon(file.icon, color: Colors.white), Spacer(), Text(file.name, textAlign: TextAlign.center), + Spacer(), + Text( + filesize(file.size), + style: TextStyle(fontSize: 10), + ), Spacer(flex: 2), ], ), diff --git a/pubspec.lock b/pubspec.lock index 4673d0e..cced30e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -50,6 +50,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0-nullsafety.1" + clipboard: + dependency: "direct main" + description: + name: clipboard + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.2+8" clock: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index cb2a015..da597b8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -97,6 +97,9 @@ dependencies: # Format file size filesize: ^1.0.4 + # Copy content to clipboard + clipboard: ^0.1.2+8 + dev_dependencies: flutter_test: sdk: flutter