Merge branch 'main' into flutter-3.22
This commit is contained in:
commit
d9edf9f05b
17 changed files with 403 additions and 336 deletions
|
|
@ -156,7 +156,8 @@ GEM
|
||||||
trailblazer-option (>= 0.1.1, < 0.2.0)
|
trailblazer-option (>= 0.1.1, < 0.2.0)
|
||||||
uber (< 0.2.0)
|
uber (< 0.2.0)
|
||||||
retriable (3.1.2)
|
retriable (3.1.2)
|
||||||
rexml (3.2.5)
|
rexml (3.2.8)
|
||||||
|
strscan (>= 3.0.9)
|
||||||
rouge (2.0.7)
|
rouge (2.0.7)
|
||||||
ruby2_keywords (0.0.4)
|
ruby2_keywords (0.0.4)
|
||||||
rubyzip (2.3.0)
|
rubyzip (2.3.0)
|
||||||
|
|
@ -169,6 +170,7 @@ GEM
|
||||||
simctl (1.6.8)
|
simctl (1.6.8)
|
||||||
CFPropertyList
|
CFPropertyList
|
||||||
naturally
|
naturally
|
||||||
|
strscan (3.1.0)
|
||||||
terminal-notifier (2.0.0)
|
terminal-notifier (2.0.0)
|
||||||
terminal-table (1.8.0)
|
terminal-table (1.8.0)
|
||||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||||
|
|
|
||||||
|
|
@ -610,7 +610,7 @@ class ChatController extends State<ChatPageWithRoom>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await Record().hasPermission() == false) return;
|
if (await AudioRecorder().hasPermission() == false) return;
|
||||||
final result = await showDialog<RecordingResult>(
|
final result = await showDialog<RecordingResult>(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,8 @@ class ChatView extends StatelessWidget {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: StreamBuilder(
|
child: StreamBuilder(
|
||||||
stream: controller.room.onUpdate.stream
|
stream: controller.room.client.onRoomState.stream
|
||||||
|
.where((update) => update.roomId == controller.room.id)
|
||||||
.rateLimit(const Duration(seconds: 1)),
|
.rateLimit(const Duration(seconds: 1)),
|
||||||
builder: (context, snapshot) => FutureBuilder(
|
builder: (context, snapshot) => FutureBuilder(
|
||||||
future: controller.loadTimelineFuture,
|
future: controller.loadTimelineFuture,
|
||||||
|
|
|
||||||
|
|
@ -144,255 +144,276 @@ class Message extends StatelessWidget {
|
||||||
setState(resetAnimateIn);
|
setState(resetAnimateIn);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return AnimatedSlide(
|
return AnimatedSize(
|
||||||
offset: Offset(0, animateIn ? 1 : 0),
|
|
||||||
duration: FluffyThemes.animationDuration,
|
duration: FluffyThemes.animationDuration,
|
||||||
curve: FluffyThemes.animationCurve,
|
curve: FluffyThemes.animationCurve,
|
||||||
child: Stack(
|
clipBehavior: Clip.none,
|
||||||
children: [
|
alignment: ownMessage ? Alignment.bottomRight : Alignment.bottomLeft,
|
||||||
Positioned(
|
child: animateIn
|
||||||
top: 0,
|
? const SizedBox(height: 0, width: double.infinity)
|
||||||
bottom: 0,
|
: Stack(
|
||||||
left: 0,
|
children: [
|
||||||
right: 0,
|
Positioned(
|
||||||
child: InkWell(
|
top: 0,
|
||||||
onTap: () => onSelect(event),
|
bottom: 0,
|
||||||
onLongPress: () => onSelect(event),
|
left: 0,
|
||||||
borderRadius:
|
right: 0,
|
||||||
BorderRadius.circular(AppConfig.borderRadius / 2),
|
child: InkWell(
|
||||||
child: Material(
|
onTap: () => onSelect(event),
|
||||||
borderRadius:
|
onLongPress: () => onSelect(event),
|
||||||
BorderRadius.circular(AppConfig.borderRadius / 2),
|
borderRadius:
|
||||||
color: selected
|
BorderRadius.circular(AppConfig.borderRadius / 2),
|
||||||
? Theme.of(context)
|
child: Material(
|
||||||
.colorScheme
|
borderRadius:
|
||||||
.secondaryContainer
|
BorderRadius.circular(AppConfig.borderRadius / 2),
|
||||||
.withAlpha(100)
|
color: selected
|
||||||
: highlightMarker
|
? Theme.of(context)
|
||||||
? Theme.of(context)
|
.colorScheme
|
||||||
.colorScheme
|
.secondaryContainer
|
||||||
.tertiaryContainer
|
.withAlpha(100)
|
||||||
.withAlpha(100)
|
: highlightMarker
|
||||||
: Colors.transparent,
|
? Theme.of(context)
|
||||||
),
|
.colorScheme
|
||||||
),
|
.tertiaryContainer
|
||||||
),
|
.withAlpha(100)
|
||||||
Row(
|
: Colors.transparent,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
mainAxisAlignment: rowMainAxisAlignment,
|
|
||||||
children: [
|
|
||||||
if (longPressSelect)
|
|
||||||
SizedBox(
|
|
||||||
height: 32,
|
|
||||||
width: Avatar.defaultSize,
|
|
||||||
child: Checkbox.adaptive(
|
|
||||||
value: selected,
|
|
||||||
shape: const CircleBorder(),
|
|
||||||
onChanged: (_) => onSelect(event),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
else if (nextEventSameSender || ownMessage)
|
|
||||||
SizedBox(
|
|
||||||
width: Avatar.defaultSize,
|
|
||||||
child: Center(
|
|
||||||
child: SizedBox(
|
|
||||||
width: 16,
|
|
||||||
height: 16,
|
|
||||||
child: event.status == EventStatus.error
|
|
||||||
? const Icon(Icons.error, color: Colors.red)
|
|
||||||
: event.fileSendingStatus != null
|
|
||||||
? const CircularProgressIndicator.adaptive(
|
|
||||||
strokeWidth: 1,
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
|
||||||
else
|
|
||||||
FutureBuilder<User?>(
|
|
||||||
future: event.fetchSenderUser(),
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
final user =
|
|
||||||
snapshot.data ?? event.senderFromMemoryOrFallback;
|
|
||||||
return Avatar(
|
|
||||||
mxContent: user.avatarUrl,
|
|
||||||
name: user.calcDisplayname(),
|
|
||||||
presenceUserId: user.stateKey,
|
|
||||||
presenceBackgroundColor:
|
|
||||||
avatarPresenceBackgroundColor,
|
|
||||||
onTap: () => onAvatarTab(event),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
Expanded(
|
Row(
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisAlignment: rowMainAxisAlignment,
|
||||||
children: [
|
children: [
|
||||||
if (!nextEventSameSender)
|
if (longPressSelect)
|
||||||
Padding(
|
SizedBox(
|
||||||
padding:
|
height: 32,
|
||||||
const EdgeInsets.only(left: 8.0, bottom: 4),
|
width: Avatar.defaultSize,
|
||||||
child: ownMessage || event.room.isDirectChat
|
child: Checkbox.adaptive(
|
||||||
? const SizedBox(height: 12)
|
value: selected,
|
||||||
: FutureBuilder<User?>(
|
shape: const CircleBorder(),
|
||||||
future: event.fetchSenderUser(),
|
onChanged: (_) => onSelect(event),
|
||||||
builder: (context, snapshot) {
|
),
|
||||||
final displayname =
|
)
|
||||||
snapshot.data?.calcDisplayname() ??
|
else if (nextEventSameSender || ownMessage)
|
||||||
event.senderFromMemoryOrFallback
|
SizedBox(
|
||||||
.calcDisplayname();
|
width: Avatar.defaultSize,
|
||||||
return Text(
|
child: Center(
|
||||||
displayname,
|
child: SizedBox(
|
||||||
style: TextStyle(
|
width: 16,
|
||||||
fontSize: 12,
|
height: 16,
|
||||||
color:
|
child: event.status == EventStatus.error
|
||||||
(Theme.of(context).brightness ==
|
? const Icon(Icons.error, color: Colors.red)
|
||||||
Brightness.light
|
: event.fileSendingStatus != null
|
||||||
? displayname.color
|
? const CircularProgressIndicator
|
||||||
: displayname.lightColorText),
|
.adaptive(
|
||||||
),
|
strokeWidth: 1,
|
||||||
);
|
)
|
||||||
},
|
: null,
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
FutureBuilder<User?>(
|
||||||
|
future: event.fetchSenderUser(),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
final user = snapshot.data ??
|
||||||
|
event.senderFromMemoryOrFallback;
|
||||||
|
return Avatar(
|
||||||
|
mxContent: user.avatarUrl,
|
||||||
|
name: user.calcDisplayname(),
|
||||||
|
presenceUserId: user.stateKey,
|
||||||
|
presenceBackgroundColor:
|
||||||
|
avatarPresenceBackgroundColor,
|
||||||
|
onTap: () => onAvatarTab(event),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
Container(
|
Expanded(
|
||||||
alignment: alignment,
|
child: Column(
|
||||||
padding: const EdgeInsets.only(left: 8),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
child: GestureDetector(
|
mainAxisSize: MainAxisSize.min,
|
||||||
onLongPress: longPressSelect
|
children: [
|
||||||
? null
|
if (!nextEventSameSender)
|
||||||
: () {
|
Padding(
|
||||||
HapticFeedback.heavyImpact();
|
padding: const EdgeInsets.only(
|
||||||
onSelect(event);
|
left: 8.0,
|
||||||
},
|
bottom: 4,
|
||||||
child: AnimatedOpacity(
|
|
||||||
opacity: animateIn
|
|
||||||
? 0
|
|
||||||
: event.redacted ||
|
|
||||||
event.messageType ==
|
|
||||||
MessageTypes.BadEncrypted ||
|
|
||||||
event.status.isSending
|
|
||||||
? 0.5
|
|
||||||
: 1,
|
|
||||||
duration: FluffyThemes.animationDuration,
|
|
||||||
curve: FluffyThemes.animationCurve,
|
|
||||||
child: Material(
|
|
||||||
color: noBubble ? Colors.transparent : color,
|
|
||||||
clipBehavior: Clip.antiAlias,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: borderRadius,
|
|
||||||
),
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
AppConfig.borderRadius,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
padding: noBubble || noPadding
|
child: ownMessage || event.room.isDirectChat
|
||||||
? EdgeInsets.zero
|
? const SizedBox(height: 12)
|
||||||
: const EdgeInsets.symmetric(
|
: FutureBuilder<User?>(
|
||||||
horizontal: 16,
|
future: event.fetchSenderUser(),
|
||||||
vertical: 8,
|
builder: (context, snapshot) {
|
||||||
),
|
final displayname = snapshot.data
|
||||||
constraints: const BoxConstraints(
|
?.calcDisplayname() ??
|
||||||
maxWidth: FluffyThemes.columnWidth * 1.5,
|
event.senderFromMemoryOrFallback
|
||||||
),
|
.calcDisplayname();
|
||||||
child: Column(
|
return Text(
|
||||||
mainAxisSize: MainAxisSize.min,
|
displayname,
|
||||||
crossAxisAlignment:
|
style: TextStyle(
|
||||||
CrossAxisAlignment.start,
|
fontSize: 12,
|
||||||
children: <Widget>[
|
color: (Theme.of(context)
|
||||||
if (event.relationshipType ==
|
.brightness ==
|
||||||
RelationshipTypes.reply)
|
Brightness.light
|
||||||
FutureBuilder<Event?>(
|
? displayname.color
|
||||||
future: event.getReplyEvent(timeline),
|
: displayname
|
||||||
builder:
|
.lightColorText),
|
||||||
(BuildContext context, snapshot) {
|
|
||||||
final replyEvent = snapshot.hasData
|
|
||||||
? snapshot.data!
|
|
||||||
: Event(
|
|
||||||
eventId: event
|
|
||||||
.relationshipEventId!,
|
|
||||||
content: {
|
|
||||||
'msgtype': 'm.text',
|
|
||||||
'body': '...',
|
|
||||||
},
|
|
||||||
senderId: event.senderId,
|
|
||||||
type: 'm.room.message',
|
|
||||||
room: event.room,
|
|
||||||
status: EventStatus.sent,
|
|
||||||
originServerTs:
|
|
||||||
DateTime.now(),
|
|
||||||
);
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.only(
|
|
||||||
bottom: 4.0,
|
|
||||||
),
|
|
||||||
child: InkWell(
|
|
||||||
borderRadius:
|
|
||||||
ReplyContent.borderRadius,
|
|
||||||
onTap: () => scrollToEventId(
|
|
||||||
replyEvent.eventId,
|
|
||||||
),
|
|
||||||
child: AbsorbPointer(
|
|
||||||
child: ReplyContent(
|
|
||||||
replyEvent,
|
|
||||||
ownMessage: ownMessage,
|
|
||||||
timeline: timeline,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
MessageContent(
|
),
|
||||||
displayEvent,
|
Container(
|
||||||
textColor: textColor,
|
alignment: alignment,
|
||||||
onInfoTab: onInfoTab,
|
padding: const EdgeInsets.only(left: 8),
|
||||||
|
child: GestureDetector(
|
||||||
|
onLongPress: longPressSelect
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
|
HapticFeedback.heavyImpact();
|
||||||
|
onSelect(event);
|
||||||
|
},
|
||||||
|
child: AnimatedOpacity(
|
||||||
|
opacity: animateIn
|
||||||
|
? 0
|
||||||
|
: event.redacted ||
|
||||||
|
event.messageType ==
|
||||||
|
MessageTypes.BadEncrypted ||
|
||||||
|
event.status.isSending
|
||||||
|
? 0.5
|
||||||
|
: 1,
|
||||||
|
duration: FluffyThemes.animationDuration,
|
||||||
|
curve: FluffyThemes.animationCurve,
|
||||||
|
child: Material(
|
||||||
|
color:
|
||||||
|
noBubble ? Colors.transparent : color,
|
||||||
|
clipBehavior: Clip.antiAlias,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: borderRadius,
|
borderRadius: borderRadius,
|
||||||
),
|
),
|
||||||
if (event.hasAggregatedEvents(
|
child: Container(
|
||||||
timeline,
|
decoration: BoxDecoration(
|
||||||
RelationshipTypes.edit,
|
borderRadius: BorderRadius.circular(
|
||||||
))
|
AppConfig.borderRadius,
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(
|
|
||||||
top: 4.0,
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
Icons.edit_outlined,
|
|
||||||
color: textColor.withAlpha(164),
|
|
||||||
size: 14,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
' - ${displayEvent.originServerTs.localizedTimeShort(context)}',
|
|
||||||
style: TextStyle(
|
|
||||||
color:
|
|
||||||
textColor.withAlpha(164),
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
padding: noBubble || noPadding
|
||||||
|
? EdgeInsets.zero
|
||||||
|
: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 16,
|
||||||
|
vertical: 8,
|
||||||
|
),
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxWidth:
|
||||||
|
FluffyThemes.columnWidth * 1.5,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.start,
|
||||||
|
children: <Widget>[
|
||||||
|
if (event.relationshipType ==
|
||||||
|
RelationshipTypes.reply)
|
||||||
|
FutureBuilder<Event?>(
|
||||||
|
future: event
|
||||||
|
.getReplyEvent(timeline),
|
||||||
|
builder: (
|
||||||
|
BuildContext context,
|
||||||
|
snapshot,
|
||||||
|
) {
|
||||||
|
final replyEvent = snapshot
|
||||||
|
.hasData
|
||||||
|
? snapshot.data!
|
||||||
|
: Event(
|
||||||
|
eventId: event
|
||||||
|
.relationshipEventId!,
|
||||||
|
content: {
|
||||||
|
'msgtype': 'm.text',
|
||||||
|
'body': '...',
|
||||||
|
},
|
||||||
|
senderId:
|
||||||
|
event.senderId,
|
||||||
|
type:
|
||||||
|
'm.room.message',
|
||||||
|
room: event.room,
|
||||||
|
status:
|
||||||
|
EventStatus.sent,
|
||||||
|
originServerTs:
|
||||||
|
DateTime.now(),
|
||||||
|
);
|
||||||
|
return Padding(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.only(
|
||||||
|
bottom: 4.0,
|
||||||
|
),
|
||||||
|
child: InkWell(
|
||||||
|
borderRadius: ReplyContent
|
||||||
|
.borderRadius,
|
||||||
|
onTap: () =>
|
||||||
|
scrollToEventId(
|
||||||
|
replyEvent.eventId,
|
||||||
|
),
|
||||||
|
child: AbsorbPointer(
|
||||||
|
child: ReplyContent(
|
||||||
|
replyEvent,
|
||||||
|
ownMessage:
|
||||||
|
ownMessage,
|
||||||
|
timeline: timeline,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
MessageContent(
|
||||||
|
displayEvent,
|
||||||
|
textColor: textColor,
|
||||||
|
onInfoTab: onInfoTab,
|
||||||
|
borderRadius: borderRadius,
|
||||||
|
),
|
||||||
|
if (event.hasAggregatedEvents(
|
||||||
|
timeline,
|
||||||
|
RelationshipTypes.edit,
|
||||||
|
))
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
top: 4.0,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize:
|
||||||
|
MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.edit_outlined,
|
||||||
|
color: textColor
|
||||||
|
.withAlpha(164),
|
||||||
|
size: 14,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
' - ${displayEvent.originServerTs.localizedTimeShort(context)}',
|
||||||
|
style: TextStyle(
|
||||||
|
color: textColor
|
||||||
|
.withAlpha(164),
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import 'package:pasteboard/pasteboard.dart';
|
||||||
import 'package:slugify/slugify.dart';
|
import 'package:slugify/slugify.dart';
|
||||||
|
|
||||||
import 'package:fluffychat/config/app_config.dart';
|
import 'package:fluffychat/config/app_config.dart';
|
||||||
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_file_extension.dart';
|
|
||||||
import 'package:fluffychat/utils/platform_infos.dart';
|
import 'package:fluffychat/utils/platform_infos.dart';
|
||||||
import 'package:fluffychat/widgets/mxc_image.dart';
|
import 'package:fluffychat/widgets/mxc_image.dart';
|
||||||
import '../../widgets/avatar.dart';
|
import '../../widgets/avatar.dart';
|
||||||
|
|
@ -465,8 +464,11 @@ class InputBar extends StatelessWidget {
|
||||||
mimeType: content.mimeType,
|
mimeType: content.mimeType,
|
||||||
bytes: data,
|
bytes: data,
|
||||||
name: content.uri.split('/').last,
|
name: content.uri.split('/').last,
|
||||||
).detectFileType;
|
);
|
||||||
room.sendFileEvent(file, shrinkImageMaxDimension: 1600);
|
room.sendFileEvent(
|
||||||
|
file,
|
||||||
|
shrinkImageMaxDimension: 1600,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
minLines: minLines,
|
minLines: minLines,
|
||||||
|
|
|
||||||
|
|
@ -28,16 +28,16 @@ class RecordingDialogState extends State<RecordingDialog> {
|
||||||
|
|
||||||
bool error = false;
|
bool error = false;
|
||||||
String? _recordedPath;
|
String? _recordedPath;
|
||||||
final _audioRecorder = Record();
|
final _audioRecorder = AudioRecorder();
|
||||||
final List<double> amplitudeTimeline = [];
|
final List<double> amplitudeTimeline = [];
|
||||||
|
|
||||||
static const int bitRate = 64000;
|
static const int bitRate = 64000;
|
||||||
static const int samplingRate = 22050;
|
static const int samplingRate = 44100;
|
||||||
|
|
||||||
Future<void> startRecording() async {
|
Future<void> startRecording() async {
|
||||||
try {
|
try {
|
||||||
final tempDir = await getTemporaryDirectory();
|
final tempDir = await getTemporaryDirectory();
|
||||||
_recordedPath =
|
final path = _recordedPath =
|
||||||
'${tempDir.path}/recording${DateTime.now().microsecondsSinceEpoch}.${RecordingDialog.recordingFileType}';
|
'${tempDir.path}/recording${DateTime.now().microsecondsSinceEpoch}.${RecordingDialog.recordingFileType}';
|
||||||
|
|
||||||
final result = await _audioRecorder.hasPermission();
|
final result = await _audioRecorder.hasPermission();
|
||||||
|
|
@ -47,9 +47,15 @@ class RecordingDialogState extends State<RecordingDialog> {
|
||||||
}
|
}
|
||||||
await WakelockPlus.enable();
|
await WakelockPlus.enable();
|
||||||
await _audioRecorder.start(
|
await _audioRecorder.start(
|
||||||
path: _recordedPath,
|
const RecordConfig(
|
||||||
bitRate: bitRate,
|
bitRate: bitRate,
|
||||||
samplingRate: samplingRate,
|
sampleRate: samplingRate,
|
||||||
|
numChannels: 1,
|
||||||
|
autoGain: true,
|
||||||
|
echoCancel: true,
|
||||||
|
noiseSuppress: true,
|
||||||
|
),
|
||||||
|
path: path,
|
||||||
);
|
);
|
||||||
setState(() => _duration = Duration.zero);
|
setState(() => _duration = Duration.zero);
|
||||||
_recorderSubscription?.cancel();
|
_recorderSubscription?.cancel();
|
||||||
|
|
|
||||||
|
|
@ -14,80 +14,90 @@ class TypingIndicators extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final typingUsers = controller.room.typingUsers
|
return StreamBuilder<Object>(
|
||||||
..removeWhere((u) => u.stateKey == Matrix.of(context).client.userID);
|
stream: controller.room.client.onSync.stream.where(
|
||||||
const topPadding = 20.0;
|
(syncUpdate) =>
|
||||||
const bottomPadding = 4.0;
|
syncUpdate.rooms?.join?[controller.room.id]?.ephemeral
|
||||||
|
?.any((ephemeral) => ephemeral.type == 'm.typing') ??
|
||||||
return Container(
|
false,
|
||||||
width: double.infinity,
|
|
||||||
alignment: Alignment.center,
|
|
||||||
child: AnimatedContainer(
|
|
||||||
constraints:
|
|
||||||
const BoxConstraints(maxWidth: FluffyThemes.columnWidth * 2.5),
|
|
||||||
height: typingUsers.isEmpty ? 0 : Avatar.defaultSize + bottomPadding,
|
|
||||||
duration: FluffyThemes.animationDuration,
|
|
||||||
curve: FluffyThemes.animationCurve,
|
|
||||||
alignment: controller.timeline!.events.isNotEmpty &&
|
|
||||||
controller.timeline!.events.first.senderId ==
|
|
||||||
Matrix.of(context).client.userID
|
|
||||||
? Alignment.topRight
|
|
||||||
: Alignment.topLeft,
|
|
||||||
clipBehavior: Clip.hardEdge,
|
|
||||||
decoration: const BoxDecoration(),
|
|
||||||
padding: const EdgeInsets.only(
|
|
||||||
left: 8.0,
|
|
||||||
bottom: bottomPadding,
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
height: Avatar.defaultSize,
|
|
||||||
width: typingUsers.length < 2
|
|
||||||
? Avatar.defaultSize
|
|
||||||
: Avatar.defaultSize + 16,
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
if (typingUsers.isNotEmpty)
|
|
||||||
Avatar(
|
|
||||||
mxContent: typingUsers.first.avatarUrl,
|
|
||||||
name: typingUsers.first.calcDisplayname(),
|
|
||||||
),
|
|
||||||
if (typingUsers.length == 2)
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 16),
|
|
||||||
child: Avatar(
|
|
||||||
mxContent: typingUsers.length == 2
|
|
||||||
? typingUsers.last.avatarUrl
|
|
||||||
: null,
|
|
||||||
name: typingUsers.length == 2
|
|
||||||
? typingUsers.last.calcDisplayname()
|
|
||||||
: '+${typingUsers.length - 1}',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(top: topPadding),
|
|
||||||
child: Material(
|
|
||||||
color: Theme.of(context).colorScheme.surfaceContainerHighest,
|
|
||||||
borderRadius: const BorderRadius.only(
|
|
||||||
topLeft: Radius.circular(2),
|
|
||||||
topRight: Radius.circular(AppConfig.borderRadius),
|
|
||||||
bottomLeft: Radius.circular(AppConfig.borderRadius),
|
|
||||||
bottomRight: Radius.circular(AppConfig.borderRadius),
|
|
||||||
),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
|
||||||
child: typingUsers.isEmpty ? null : const _TypingDots(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
builder: (context, _) {
|
||||||
|
final typingUsers = controller.room.typingUsers
|
||||||
|
..removeWhere((u) => u.stateKey == Matrix.of(context).client.userID);
|
||||||
|
const topPadding = 20.0;
|
||||||
|
const bottomPadding = 4.0;
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: AnimatedContainer(
|
||||||
|
constraints:
|
||||||
|
const BoxConstraints(maxWidth: FluffyThemes.columnWidth * 2.5),
|
||||||
|
height:
|
||||||
|
typingUsers.isEmpty ? 0 : Avatar.defaultSize + bottomPadding,
|
||||||
|
duration: FluffyThemes.animationDuration,
|
||||||
|
curve: FluffyThemes.animationCurve,
|
||||||
|
alignment: controller.timeline!.events.isNotEmpty &&
|
||||||
|
controller.timeline!.events.first.senderId ==
|
||||||
|
Matrix.of(context).client.userID
|
||||||
|
? Alignment.topRight
|
||||||
|
: Alignment.topLeft,
|
||||||
|
clipBehavior: Clip.hardEdge,
|
||||||
|
decoration: const BoxDecoration(),
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
left: 8.0,
|
||||||
|
bottom: bottomPadding,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: Avatar.defaultSize,
|
||||||
|
width: typingUsers.length < 2
|
||||||
|
? Avatar.defaultSize
|
||||||
|
: Avatar.defaultSize + 16,
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
if (typingUsers.isNotEmpty)
|
||||||
|
Avatar(
|
||||||
|
mxContent: typingUsers.first.avatarUrl,
|
||||||
|
name: typingUsers.first.calcDisplayname(),
|
||||||
|
),
|
||||||
|
if (typingUsers.length == 2)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 16),
|
||||||
|
child: Avatar(
|
||||||
|
mxContent: typingUsers.length == 2
|
||||||
|
? typingUsers.last.avatarUrl
|
||||||
|
: null,
|
||||||
|
name: typingUsers.length == 2
|
||||||
|
? typingUsers.last.calcDisplayname()
|
||||||
|
: '+${typingUsers.length - 1}',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: topPadding),
|
||||||
|
child: Material(
|
||||||
|
color: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||||
|
borderRadius: const BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(2),
|
||||||
|
topRight: Radius.circular(AppConfig.borderRadius),
|
||||||
|
bottomLeft: Radius.circular(AppConfig.borderRadius),
|
||||||
|
bottomRight: Radius.circular(AppConfig.borderRadius),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
child: typingUsers.isEmpty ? null : const _TypingDots(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,8 @@ class ChatAccessSettingsPageView extends StatelessWidget {
|
||||||
),
|
),
|
||||||
body: MaxWidthBody(
|
body: MaxWidthBody(
|
||||||
child: StreamBuilder<Object>(
|
child: StreamBuilder<Object>(
|
||||||
stream: room.onUpdate.stream,
|
stream: room.client.onRoomState.stream
|
||||||
|
.where((update) => update.roomId == controller.room.id),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
final canonicalAlias = room.canonicalAlias;
|
final canonicalAlias = room.canonicalAlias;
|
||||||
final altAliases = room
|
final altAliases = room
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,8 @@ class ChatDetailsView extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
return StreamBuilder(
|
return StreamBuilder(
|
||||||
stream: room.onUpdate.stream,
|
stream: room.client.onRoomState.stream
|
||||||
|
.where((update) => update.roomId == room.id),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
var members = room.getParticipants().toList()
|
var members = room.getParticipants().toList()
|
||||||
..sort((b, a) => a.powerLevel.compareTo(b.powerLevel));
|
..sort((b, a) => a.powerLevel.compareTo(b.powerLevel));
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,8 @@ class ChatEncryptionSettingsView extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
StreamBuilder(
|
StreamBuilder(
|
||||||
stream: room.onUpdate.stream,
|
stream: room.client.onRoomState.stream
|
||||||
|
.where((update) => update.roomId == controller.room.id),
|
||||||
builder: (context, snapshot) =>
|
builder: (context, snapshot) =>
|
||||||
FutureBuilder<List<DeviceKeys>>(
|
FutureBuilder<List<DeviceKeys>>(
|
||||||
future: room.getUserDeviceKeys(),
|
future: room.getUserDeviceKeys(),
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,8 @@ class InvitationSelectionView extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
StreamBuilder<Object>(
|
StreamBuilder<Object>(
|
||||||
stream: room.onUpdate.stream,
|
stream: room.client.onRoomState.stream
|
||||||
|
.where((update) => update.roomId == room.id),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
final participants =
|
final participants =
|
||||||
room.getParticipants().map((user) => user.id).toSet();
|
room.getParticipants().map((user) => user.id).toSet();
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,8 @@ class MultipleEmotesSettingsView extends StatelessWidget {
|
||||||
title: Text(L10n.of(context)!.emotePacks),
|
title: Text(L10n.of(context)!.emotePacks),
|
||||||
),
|
),
|
||||||
body: StreamBuilder(
|
body: StreamBuilder(
|
||||||
stream: room.onUpdate.stream,
|
stream: room.client.onRoomState.stream
|
||||||
|
.where((update) => update.roomId == room.id),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
final packStateEvents = room.states['im.ponies.room_emotes'];
|
final packStateEvents = room.states['im.ponies.room_emotes'];
|
||||||
// we need to manually convert the map using Map.of, otherwise assigning null will throw a type error.
|
// we need to manually convert the map using Map.of, otherwise assigning null will throw a type error.
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,7 @@ abstract class ClientManager {
|
||||||
},
|
},
|
||||||
nativeImplementations: nativeImplementations,
|
nativeImplementations: nativeImplementations,
|
||||||
customImageResizer: PlatformInfos.isMobile ? customImageResizer : null,
|
customImageResizer: PlatformInfos.isMobile ? customImageResizer : null,
|
||||||
|
defaultNetworkRequestTimeout: const Duration(minutes: 5),
|
||||||
enableDehydratedDevices: true,
|
enableDehydratedDevices: true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,12 @@ Future<DatabaseApi> flutterMatrixSdkDatabaseBuilder(Client client) async {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Delete database file:
|
||||||
|
if (database == null && !kIsWeb) {
|
||||||
|
final dbFile = File(await _getDatabasePath(client.clientName));
|
||||||
|
if (await dbFile.exists()) await dbFile.delete();
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Send error notification:
|
// Send error notification:
|
||||||
final l10n = lookupL10n(PlatformDispatcher.instance.locale);
|
final l10n = lookupL10n(PlatformDispatcher.instance.locale);
|
||||||
|
|
@ -61,9 +67,6 @@ Future<MatrixSdkDatabase> _constructDatabase(Client client) async {
|
||||||
|
|
||||||
final cipher = await getDatabaseCipher();
|
final cipher = await getDatabaseCipher();
|
||||||
|
|
||||||
final databaseDirectory = PlatformInfos.isIOS || PlatformInfos.isMacOS
|
|
||||||
? await getLibraryDirectory()
|
|
||||||
: await getApplicationSupportDirectory();
|
|
||||||
Directory? fileStorageLocation;
|
Directory? fileStorageLocation;
|
||||||
try {
|
try {
|
||||||
fileStorageLocation = await getTemporaryDirectory();
|
fileStorageLocation = await getTemporaryDirectory();
|
||||||
|
|
@ -73,7 +76,7 @@ Future<MatrixSdkDatabase> _constructDatabase(Client client) async {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final path = join(databaseDirectory.path, '${client.clientName}.sqlite');
|
final path = await _getDatabasePath(client.clientName);
|
||||||
|
|
||||||
// fix dlopen for old Android
|
// fix dlopen for old Android
|
||||||
await applyWorkaroundToOpenSqlCipherOnOldAndroidVersions();
|
await applyWorkaroundToOpenSqlCipherOnOldAndroidVersions();
|
||||||
|
|
@ -118,6 +121,14 @@ Future<MatrixSdkDatabase> _constructDatabase(Client client) async {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<String> _getDatabasePath(String clientName) async {
|
||||||
|
final databaseDirectory = PlatformInfos.isIOS || PlatformInfos.isMacOS
|
||||||
|
? await getLibraryDirectory()
|
||||||
|
: await getApplicationSupportDirectory();
|
||||||
|
|
||||||
|
return join(databaseDirectory.path, '$clientName.sqlite');
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _migrateLegacyLocation(
|
Future<void> _migrateLegacyLocation(
|
||||||
String sqlFilePath,
|
String sqlFilePath,
|
||||||
String clientName,
|
String clientName,
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import macos_window_utils
|
||||||
import package_info_plus
|
import package_info_plus
|
||||||
import pasteboard
|
import pasteboard
|
||||||
import path_provider_foundation
|
import path_provider_foundation
|
||||||
import record_macos
|
import record_darwin
|
||||||
import share_plus
|
import share_plus
|
||||||
import shared_preferences_foundation
|
import shared_preferences_foundation
|
||||||
import sqflite
|
import sqflite
|
||||||
|
|
@ -55,7 +55,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||||
PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin"))
|
PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin"))
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
RecordMacosPlugin.register(with: registry.registrar(forPlugin: "RecordMacosPlugin"))
|
RecordPlugin.register(with: registry.registrar(forPlugin: "RecordPlugin"))
|
||||||
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
|
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
|
||||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||||
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
||||||
|
|
|
||||||
48
pubspec.lock
48
pubspec.lock
|
|
@ -1210,10 +1210,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: matrix
|
name: matrix
|
||||||
sha256: "8610e6d207d6b667e4fe9e769d5b479db27aa1f80570880d3f171a5d3ff49d1a"
|
sha256: b96f16ec227138a61d148f2812c4d558b2930edbb6cd05d03b3a41c4fffd2f47
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.29.2"
|
version: "0.29.7"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1618,50 +1618,58 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: record
|
name: record
|
||||||
sha256: f703397f5a60d9b2b655b3acc94ba079b2d9a67dc0725bdb90ef2fee2441ebf7
|
sha256: "113b368168c49c78902ab37c2b354dea30a0aec5bdeca434073826b6ea73eca1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.4.4"
|
version: "5.0.5"
|
||||||
|
record_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: record_android
|
||||||
|
sha256: "0df98e05873b22b443309e289bf1eb3b5b9a60e7779134334e2073eb0763a992"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
|
record_darwin:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: record_darwin
|
||||||
|
sha256: ee8cb1bb1712d7ce38140ecabe70e5c286c02f05296d66043bee865ace7eb1b9
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.1"
|
||||||
record_linux:
|
record_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: record_linux
|
name: record_linux
|
||||||
sha256: "348db92c4ec1b67b1b85d791381c8c99d7c6908de141e7c9edc20dad399b15ce"
|
sha256: "7d0e70cd51635128fe9d37d89bafd6011d7cbba9af8dc323079ae60f23546aef"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.4.1"
|
version: "0.7.1"
|
||||||
record_macos:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: record_macos
|
|
||||||
sha256: d1d0199d1395f05e218207e8cacd03eb9dc9e256ddfe2cfcbbb90e8edea06057
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.2.2"
|
|
||||||
record_platform_interface:
|
record_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: record_platform_interface
|
name: record_platform_interface
|
||||||
sha256: "7a2d4ce7ac3752505157e416e4e0d666a54b1d5d8601701b7e7e5e30bec181b4"
|
sha256: "3a4b56e94ecd2a0b2b43eb1fa6f94c5b8484334f5d38ef43959c4bf97fb374cf"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.0"
|
version: "1.0.2"
|
||||||
record_web:
|
record_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: record_web
|
name: record_web
|
||||||
sha256: "219ffb4ca59b4338117857db56d3ffadbde3169bcaf1136f5f4d4656f4a2372d"
|
sha256: "24847cdbcf999f7a5762170792f622ac844858766becd0f2370ec8ae22f7526e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.0"
|
version: "1.0.5"
|
||||||
record_windows:
|
record_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: record_windows
|
name: record_windows
|
||||||
sha256: "42d545155a26b20d74f5107648dbb3382dbbc84dc3f1adc767040359e57a1345"
|
sha256: "39998b3ea7d8d28b04159d82220e6e5e32a7c357c6fb2794f5736beea272f6c3"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.1"
|
version: "1.0.2"
|
||||||
remove_emoji:
|
remove_emoji:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,8 @@ dependencies:
|
||||||
keyboard_shortcuts: ^0.1.4
|
keyboard_shortcuts: ^0.1.4
|
||||||
latlong2: ^0.9.1
|
latlong2: ^0.9.1
|
||||||
linkify: ^5.0.0
|
linkify: ^5.0.0
|
||||||
matrix: ^0.29.2
|
matrix: ^0.29.7
|
||||||
native_imaging: ^0.1.0
|
native_imaging: ^0.1.1
|
||||||
package_info_plus: ^6.0.0
|
package_info_plus: ^6.0.0
|
||||||
pasteboard: ^0.2.0
|
pasteboard: ^0.2.0
|
||||||
path: ^1.9.0
|
path: ^1.9.0
|
||||||
|
|
@ -76,7 +76,7 @@ dependencies:
|
||||||
punycode: ^1.0.0
|
punycode: ^1.0.0
|
||||||
qr_code_scanner: ^1.0.1
|
qr_code_scanner: ^1.0.1
|
||||||
receive_sharing_intent: 1.4.5 # Update needs more work
|
receive_sharing_intent: 1.4.5 # Update needs more work
|
||||||
record: 4.4.4 # Upgrade to 5 currently breaks playing on iOS
|
record: ^5.0.5
|
||||||
scroll_to_index: ^3.0.1
|
scroll_to_index: ^3.0.1
|
||||||
share_plus: ^9.0.0
|
share_plus: ^9.0.0
|
||||||
shared_preferences: ^2.2.0 # Pinned because https://github.com/flutter/flutter/issues/118401
|
shared_preferences: ^2.2.0 # Pinned because https://github.com/flutter/flutter/issues/118401
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue