1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2024-11-22 12:59:21 +00:00

Can copy message to clipboard

This commit is contained in:
Pierre HUBERT 2021-03-11 17:04:18 +01:00
parent 8705aa1b0d
commit 217111e3fd
5 changed files with 43 additions and 136 deletions

View File

@ -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;

View File

@ -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<AudioPlayerWidget> {
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: <Widget>[
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: <Widget>[
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);
}
}

View File

@ -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<ConversationFileWidget> {
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),
],
),

View File

@ -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:

View File

@ -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