Skip to content

Commit decb795

Browse files
Added sample
1 parent bd1bd4a commit decb795

File tree

1 file changed

+251
-0
lines changed

1 file changed

+251
-0
lines changed
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:syncfusion_flutter_core/localizations.dart';
3+
4+
import '../common/pdfviewer_helper.dart';
5+
6+
/// Width of the text selection menu
7+
const double kTextSelectionMenuWidth = 191.0;
8+
9+
/// Height of the text selection menu
10+
const double kTextSelectionMenuHeight = 216.0;
11+
12+
/// Height of the text selection menu item
13+
const double kTextSelectionMenuItemHeight = 40.0;
14+
15+
/// Margin of the text selection menu
16+
final double kTextSelectionMenuMargin = kIsDesktop ? 10 : 32;
17+
18+
/// A text selection menu that can be used to display a list of actions
19+
class TextSelectionMenu extends StatefulWidget {
20+
/// Creates a text selection menu
21+
const TextSelectionMenu(
22+
{super.key,
23+
this.textDirection,
24+
this.onSelected,
25+
this.themeData,
26+
this.localizations});
27+
28+
/// Called when an item is selected
29+
final void Function(String)? onSelected;
30+
31+
/// The text direction to use for rendering the text selection menu.
32+
final TextDirection? textDirection;
33+
34+
/// The theme data of the text selection menu.
35+
final ThemeData? themeData;
36+
37+
///The localizations of the text selection menu.
38+
final SfLocalizations? localizations;
39+
40+
@override
41+
State<TextSelectionMenu> createState() => _TextSelectionMenuState();
42+
}
43+
44+
class _TextSelectionMenuState extends State<TextSelectionMenu> {
45+
@override
46+
Widget build(BuildContext context) {
47+
return Container(
48+
height: kTextSelectionMenuHeight,
49+
decoration: ShapeDecoration(
50+
color: (widget.themeData!.colorScheme.brightness == Brightness.light)
51+
? Colors.white
52+
: const Color(0xFF303030),
53+
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),
54+
shadows: const <BoxShadow>[
55+
BoxShadow(
56+
color: Color(0x1E000000),
57+
blurRadius: 10,
58+
offset: Offset(0, 1),
59+
),
60+
BoxShadow(
61+
color: Color(0x23000000),
62+
blurRadius: 5,
63+
offset: Offset(0, 4),
64+
),
65+
BoxShadow(
66+
color: Color(0x05000000),
67+
blurRadius: 4,
68+
offset: Offset(0, 2),
69+
spreadRadius: -1,
70+
)
71+
],
72+
),
73+
child: Padding(
74+
padding: const EdgeInsets.only(top: 8.0, bottom: 8.0),
75+
child: IntrinsicWidth(
76+
child: SingleChildScrollView(
77+
child: ListBody(
78+
children: <Widget>[
79+
TextSelectionMenuItem(
80+
title: widget.localizations!.pdfTextSelectionMenuCopyLabel,
81+
mode: 'Copy',
82+
onSelected: widget.onSelected,
83+
textDirection: widget.textDirection,
84+
themeData: widget.themeData,
85+
),
86+
TextSelectionMenuItem(
87+
title:
88+
widget.localizations!.pdfTextSelectionMenuHighlightLabel,
89+
mode: 'Highlight',
90+
onSelected: widget.onSelected,
91+
textDirection: widget.textDirection,
92+
themeData: widget.themeData,
93+
),
94+
TextSelectionMenuItem(
95+
title:
96+
widget.localizations!.pdfTextSelectionMenuUnderlineLabel,
97+
mode: 'Underline',
98+
onSelected: widget.onSelected,
99+
textDirection: widget.textDirection,
100+
themeData: widget.themeData,
101+
),
102+
TextSelectionMenuItem(
103+
title: widget
104+
.localizations!.pdfTextSelectionMenuStrikethroughLabel,
105+
mode: 'Strikethrough',
106+
onSelected: widget.onSelected,
107+
textDirection: widget.textDirection,
108+
themeData: widget.themeData,
109+
),
110+
TextSelectionMenuItem(
111+
title:
112+
widget.localizations!.pdfTextSelectionMenuSquigglyLabel,
113+
mode: 'Squiggly',
114+
onSelected: widget.onSelected,
115+
textDirection: widget.textDirection,
116+
themeData: widget.themeData,
117+
),
118+
],
119+
),
120+
),
121+
),
122+
),
123+
);
124+
}
125+
}
126+
127+
/// A text selection menu item that can be used to display a list of actions
128+
class TextSelectionMenuItem extends StatefulWidget {
129+
/// Creates a text selection menu item
130+
const TextSelectionMenuItem(
131+
{required this.title,
132+
required this.mode,
133+
required this.onSelected,
134+
this.textDirection,
135+
this.themeData,
136+
super.key});
137+
138+
/// Title of the text selection menu item
139+
final String title;
140+
141+
/// Mode of the text selection menu item
142+
final String mode;
143+
144+
/// Called when an item is selected
145+
final void Function(String)? onSelected;
146+
147+
/// The text direction to use for rendering the title.
148+
final TextDirection? textDirection;
149+
150+
/// The theme data of the text selection menu item.
151+
final ThemeData? themeData;
152+
153+
@override
154+
State<TextSelectionMenuItem> createState() => _TextSelectionMenuItemState();
155+
}
156+
157+
class _TextSelectionMenuItemState extends State<TextSelectionMenuItem> {
158+
bool _isHovering = false;
159+
160+
@override
161+
Widget build(BuildContext context) {
162+
return GestureDetector(
163+
onTap: () {
164+
widget.onSelected?.call(widget.mode);
165+
},
166+
child: MouseRegion(
167+
onEnter: (_) {
168+
setState(() {
169+
_isHovering = true;
170+
});
171+
},
172+
onExit: (_) {
173+
setState(() {
174+
_isHovering = false;
175+
});
176+
},
177+
child: Directionality(
178+
textDirection: widget.textDirection ?? TextDirection.ltr,
179+
child: Container(
180+
height: kTextSelectionMenuItemHeight,
181+
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
182+
decoration: BoxDecoration(
183+
color: _isHovering
184+
? (widget.themeData!.colorScheme.brightness ==
185+
Brightness.light)
186+
? Colors.grey.withOpacity(0.2)
187+
: Colors.grey.withOpacity(0.5)
188+
: Colors.transparent,
189+
),
190+
child: Row(
191+
children: <Widget>[
192+
_getIcon(widget.mode),
193+
const Divider(
194+
indent: 12,
195+
),
196+
Text(
197+
widget.title,
198+
overflow: TextOverflow.ellipsis,
199+
style: widget.themeData!.textTheme.bodyMedium!.copyWith(
200+
fontSize: 14,
201+
color: widget.themeData!.brightness == Brightness.light
202+
? Colors.black.withOpacity(0.87)
203+
: Colors.white.withOpacity(0.87),
204+
),
205+
),
206+
],
207+
),
208+
),
209+
),
210+
),
211+
);
212+
}
213+
214+
Widget _getIcon(String mode) {
215+
if (mode == 'Copy') {
216+
return Icon(
217+
Icons.copy,
218+
size: 16,
219+
color: (widget.themeData!.colorScheme.brightness == Brightness.light)
220+
? Colors.black.withOpacity(0.87)
221+
: Colors.white.withOpacity(0.87),
222+
);
223+
}
224+
mode = mode.toLowerCase().replaceAll(RegExp(r' '), '');
225+
return ImageIcon(
226+
AssetImage('assets/$mode.png', package: 'syncfusion_flutter_pdfviewer'),
227+
size: 16,
228+
color: (widget.themeData!.colorScheme.brightness == Brightness.light)
229+
? Colors.black.withOpacity(0.87)
230+
: Colors.white.withOpacity(0.87),
231+
);
232+
}
233+
}
234+
235+
/// The location of the text selection menu
236+
enum TextSelectionMenuLocation {
237+
/// Left
238+
left,
239+
240+
/// Top
241+
top,
242+
243+
/// Right
244+
right,
245+
246+
/// Bottom
247+
bottom,
248+
249+
/// Center
250+
center
251+
}

0 commit comments

Comments
 (0)