1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import 'package:flutter/material.dart';
6
7typedef _TextTransformer = Widget Function(String name, String text);
8
9// From https://en.wikiquote.org/wiki/2001:_A_Space_Odyssey_(film)
10const String _kDialogText = '''
11Dave: Open the pod bay doors, please, HAL. Open the pod bay doors, please, HAL. Hello, HAL. Do you read me? Hello, HAL. Do you read me? Do you read me, HAL?
12HAL: Affirmative, Dave. I read you.
13Dave: Open the pod bay doors, HAL.
14HAL: I'm sorry, Dave. I'm afraid I can't do that.
15Dave: What's the problem?
16HAL: I think you know what the problem is just as well as I do.
17Dave: What are you talking about, HAL?
18HAL: This mission is too important for me to allow you to jeopardize it.''';
19
20// [["Dave", "Open the pod bay..."] ...]
21final List<List<String>> _kNameLines = _kDialogText
22 .split('\n')
23 .map<List<String>>((String line) => line.split(':'))
24 .toList();
25
26final TextStyle _kDaveStyle = TextStyle(color: Colors.indigo.shade400, height: 1.8);
27final TextStyle _kHalStyle = TextStyle(color: Colors.red.shade400, fontFamily: 'monospace');
28const TextStyle _kBold = TextStyle(fontWeight: FontWeight.bold);
29const TextStyle _kUnderline = TextStyle(
30 decoration: TextDecoration.underline,
31 decorationColor: Color(0xFF000000),
32 decorationStyle: TextDecorationStyle.wavy,
33);
34
35Widget toStyledText(String name, String text) {
36 final TextStyle lineStyle = (name == 'Dave') ? _kDaveStyle : _kHalStyle;
37 return RichText(
38 key: Key(text),
39 text: TextSpan(
40 style: lineStyle,
41 children: <TextSpan>[
42 TextSpan(
43 style: _kBold,
44 children: <TextSpan>[
45 TextSpan(style: _kUnderline, text: name),
46 const TextSpan(text: ':'),
47 ],
48 ),
49 TextSpan(text: text),
50 ],
51 ),
52 );
53}
54
55Widget toPlainText(String name, String text) => Text('$name:$text');
56
57class SpeakerSeparator extends StatelessWidget {
58 const SpeakerSeparator({super.key});
59
60 @override
61 Widget build(BuildContext context) {
62 return Container(
63 constraints: const BoxConstraints.expand(height: 0.0),
64 margin: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 64.0),
65 decoration: const BoxDecoration(
66 border: Border(bottom: BorderSide(color: Color.fromARGB(24, 0, 0, 0))),
67 ),
68 );
69 }
70}
71
72class StyledTextDemo extends StatefulWidget {
73 const StyledTextDemo({super.key});
74
75 @override
76 State<StyledTextDemo> createState() => _StyledTextDemoState();
77}
78
79class _StyledTextDemoState extends State<StyledTextDemo> {
80 _TextTransformer _toText = toStyledText;
81
82 void _handleTap() {
83 setState(() {
84 _toText = (_toText == toPlainText) ? toStyledText : toPlainText;
85 });
86 }
87
88 @override
89 Widget build(BuildContext context) {
90 return GestureDetector(
91 onTap: _handleTap,
92 child: Container(
93 padding: const EdgeInsets.symmetric(horizontal: 8.0),
94 child: Column(
95 mainAxisAlignment: MainAxisAlignment.center,
96 crossAxisAlignment: CrossAxisAlignment.start,
97 children:
98 _kNameLines
99 .map<Widget>(
100 (List<String> nameAndText) => _toText(nameAndText[0], nameAndText[1]),
101 )
102 .expand((Widget line) => <Widget>[line, const SpeakerSeparator()])
103 .toList()
104 ..removeLast(),
105 ),
106 ),
107 );
108 }
109}
110
111void main() {
112 runApp(
113 MaterialApp(
114 home: Scaffold(
115 appBar: AppBar(title: const Text('Hal and Dave')),
116 body: Material(color: Colors.grey.shade50, child: const StyledTextDemo()),
117 ),
118 ),
119 );
120}
121