feat: Make all text in chat selectable on desktop
This commit is contained in:
parent
7d7e234142
commit
809ee213b6
4 changed files with 222 additions and 194 deletions
|
|
@ -31,7 +31,8 @@ class ChatEventList extends StatelessWidget {
|
||||||
thisEventsKeyMap[controller.timeline!.events[i].eventId] = i;
|
thisEventsKeyMap[controller.timeline!.events[i].eventId] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ListView.custom(
|
return SelectionArea(
|
||||||
|
child: ListView.custom(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
top: 16,
|
top: 16,
|
||||||
bottom: 4,
|
bottom: 4,
|
||||||
|
|
@ -130,6 +131,7 @@ class ChatEventList extends StatelessWidget {
|
||||||
findChildIndexCallback: (key) =>
|
findChildIndexCallback: (key) =>
|
||||||
controller.findChildIndexCallback(key, thisEventsKeyMap),
|
controller.findChildIndexCallback(key, thisEventsKeyMap),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import 'package:fluffychat/utils/string_color.dart';
|
||||||
import 'package:fluffychat/widgets/avatar.dart';
|
import 'package:fluffychat/widgets/avatar.dart';
|
||||||
import 'package:fluffychat/widgets/matrix.dart';
|
import 'package:fluffychat/widgets/matrix.dart';
|
||||||
import '../../../config/app_config.dart';
|
import '../../../config/app_config.dart';
|
||||||
|
import '../../../widgets/hover_builder.dart';
|
||||||
import 'message_content.dart';
|
import 'message_content.dart';
|
||||||
import 'message_reactions.dart';
|
import 'message_reactions.dart';
|
||||||
import 'reply_content.dart';
|
import 'reply_content.dart';
|
||||||
|
|
@ -44,10 +45,6 @@ class Message extends StatelessWidget {
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Indicates wheither the user may use a mouse instead
|
|
||||||
/// of touchscreen.
|
|
||||||
static bool useMouse = false;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (!{
|
if (!{
|
||||||
|
|
@ -117,15 +114,26 @@ class Message extends StatelessWidget {
|
||||||
: Theme.of(context).colorScheme.primaryContainer;
|
: Theme.of(context).colorScheme.primaryContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
final row = Row(
|
final row = InkWell(
|
||||||
|
onTap: longPressSelect ? () => onSelect!(event) : null,
|
||||||
|
onLongPress: () => onSelect!(event),
|
||||||
|
child: HoverBuilder(
|
||||||
|
builder: (context, hovered) => Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: rowMainAxisAlignment,
|
mainAxisAlignment: rowMainAxisAlignment,
|
||||||
children: [
|
children: [
|
||||||
sameSender || ownMessage
|
if (hovered || selected)
|
||||||
? SizedBox(
|
SizedBox(
|
||||||
|
width: Avatar.defaultSize,
|
||||||
|
height: Avatar.defaultSize - 8,
|
||||||
|
child: Checkbox.adaptive(
|
||||||
|
value: selected,
|
||||||
|
onChanged: (_) => onSelect?.call(event),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else if (sameSender || ownMessage)
|
||||||
|
SizedBox(
|
||||||
width: Avatar.defaultSize,
|
width: Avatar.defaultSize,
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 8.0),
|
|
||||||
child: Center(
|
child: Center(
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: 16,
|
width: 16,
|
||||||
|
|
@ -139,9 +147,9 @@ class Message extends StatelessWidget {
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
: FutureBuilder<User?>(
|
else
|
||||||
|
FutureBuilder<User?>(
|
||||||
future: event.fetchSenderUser(),
|
future: event.fetchSenderUser(),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
final user =
|
final user =
|
||||||
|
|
@ -205,9 +213,7 @@ class Message extends StatelessWidget {
|
||||||
constraints: const BoxConstraints(
|
constraints: const BoxConstraints(
|
||||||
maxWidth: FluffyThemes.columnWidth * 1.5,
|
maxWidth: FluffyThemes.columnWidth * 1.5,
|
||||||
),
|
),
|
||||||
child: Stack(
|
child: Column(
|
||||||
children: <Widget>[
|
|
||||||
Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
|
|
@ -284,8 +290,6 @@ class Message extends StatelessWidget {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -293,6 +297,8 @@ class Message extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
Widget container;
|
Widget container;
|
||||||
if (event.hasAggregatedEvents(timeline, RelationshipTypes.reaction) ||
|
if (event.hasAggregatedEvents(timeline, RelationshipTypes.reaction) ||
|
||||||
|
|
@ -392,12 +398,6 @@ class Message extends StatelessWidget {
|
||||||
direction: SwipeDirection.endToStart,
|
direction: SwipeDirection.endToStart,
|
||||||
onSwipe: onSwipe,
|
onSwipe: onSwipe,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: MouseRegion(
|
|
||||||
onEnter: (_) => useMouse = true,
|
|
||||||
onExit: (_) => useMouse = false,
|
|
||||||
child: InkWell(
|
|
||||||
onTap: longPressSelect || useMouse ? () => onSelect!(event) : null,
|
|
||||||
onLongPress: () => onSelect!(event),
|
|
||||||
child: Container(
|
child: Container(
|
||||||
color: selected
|
color: selected
|
||||||
? Theme.of(context).primaryColor.withAlpha(100)
|
? Theme.of(context).primaryColor.withAlpha(100)
|
||||||
|
|
@ -412,8 +412,6 @@ class Message extends StatelessWidget {
|
||||||
child: container,
|
child: container,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ class CustomScrollBehavior extends MaterialScrollBehavior {
|
||||||
@override
|
@override
|
||||||
Set<PointerDeviceKind> get dragDevices => {
|
Set<PointerDeviceKind> get dragDevices => {
|
||||||
PointerDeviceKind.touch,
|
PointerDeviceKind.touch,
|
||||||
PointerDeviceKind.mouse,
|
|
||||||
PointerDeviceKind.trackpad,
|
PointerDeviceKind.trackpad,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
29
lib/widgets/hover_builder.dart
Normal file
29
lib/widgets/hover_builder.dart
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class HoverBuilder extends StatefulWidget {
|
||||||
|
final Widget Function(BuildContext context, bool hovered) builder;
|
||||||
|
const HoverBuilder({required this.builder, super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<HoverBuilder> createState() => _HoverBuilderState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HoverBuilderState extends State<HoverBuilder> {
|
||||||
|
bool hovered = false;
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MouseRegion(
|
||||||
|
onEnter: (_) => hovered
|
||||||
|
? null
|
||||||
|
: setState(() {
|
||||||
|
hovered = true;
|
||||||
|
}),
|
||||||
|
onExit: (_) => !hovered
|
||||||
|
? null
|
||||||
|
: setState(() {
|
||||||
|
hovered = false;
|
||||||
|
}),
|
||||||
|
child: widget.builder(context, hovered),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue