Last active
May 16, 2024 12:23
-
-
Save bryantwilliam/c2de6910249c47350dc966a85a37ccfb to your computer and use it in GitHub Desktop.
highlight selected html in flutter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
import 'package:flutter_riverpod/flutter_riverpod.dart'; | |
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart'; | |
import 'package:html/dom.dart' as dom; | |
Future<void> main() async { | |
runApp(const ProviderScope(child: MyApp())); | |
} | |
class MyApp extends ConsumerStatefulWidget { | |
const MyApp({super.key}); | |
@override | |
ConsumerState<MyApp> createState() => _MyAppState(); | |
} | |
class _MyAppState extends ConsumerState<MyApp> { | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
title: 'Flutter Demo', | |
theme: ThemeData( | |
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), | |
useMaterial3: true, | |
), | |
home: Scaffold( | |
body: Center( | |
child: HtmlWidget( | |
html, | |
// specify custom styling for an element | |
// see supported inline styling below | |
customStylesBuilder: (element) { | |
if (element.classes.contains('foo')) { | |
return {'color': 'red'}; | |
} | |
return null; | |
}, | |
customWidgetBuilder: (element) { | |
final highlightedElement = ref.read(highlightedElementProvider); | |
print("highlightedElement: $highlightedElement"); | |
// maybe set ids for each element in here? | |
// or maybe just set the background color here. | |
if (isSameHtmlElement(element, highlightedElement)) { | |
// Uncomment and see what happens (it works, but the highlighting from below stops working): | |
//element.text = "Selected"; | |
} | |
return null; | |
}, | |
factoryBuilder: () { | |
return CustomWidgetFactory(ref); | |
}, | |
// this callback will be triggered when user taps a link | |
onTapUrl: (url) { | |
print('tapped $url'); | |
return false; | |
}, | |
// select the render mode for HTML body | |
// by default, a simple `Column` is rendered | |
// consider using `ListView` or `SliverList` for better performance | |
renderMode: RenderMode.column, | |
// set the default styling for text | |
textStyle: const TextStyle(fontSize: 15), | |
// triggers a rebuild if this value changes. | |
rebuildTriggers: [ref.read(highlightedElementProvider)], | |
), | |
), | |
), | |
); | |
} | |
} | |
bool isSameHtmlElement(dom.Element element, dom.Element? otherElement) { | |
// Could maybe use id instead of innerHtml to check, because it's unique for every element (first need to make every element have an id). | |
return element.innerHtml == otherElement?.innerHtml; | |
} | |
final highlightedElementProvider = StateProvider<dom.Element?>((ref) => null); | |
class CustomWidgetFactory extends WidgetFactory { | |
WidgetRef ref; | |
CustomWidgetFactory(this.ref); | |
@override | |
Widget? buildText( | |
BuildTree tree, InheritedProperties resolved, InlineSpan text) { | |
final highlightedElement = ref.watch(highlightedElementProvider); | |
return SelectableText.rich( | |
TextSpan( | |
style: TextStyle( | |
backgroundColor: isSameHtmlElement(tree.element, highlightedElement) | |
? Colors.red | |
: null, | |
), | |
children: <InlineSpan>[text], | |
), | |
onSelectionChanged: | |
(TextSelection selection, SelectionChangedCause? cause) { | |
// Can use the offsets and direction of highlight | |
print("selection: $selection"); | |
String textInside = selection.textInside(text.toPlainText()); | |
print("plain text selected: $textInside"); | |
ref.read(highlightedElementProvider.notifier).state = tree.element; | |
}, | |
); | |
} | |
} | |
String html = ''' | |
<html><body><article><h1>Thunder (mascot)</h1><p>Thunder is the stage name for the horse who is the official live animal mascot for the Denver Broncos</p><p>test</p></article></body></html> | |
'''; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment